Cython 为应评估为 0.5 的表达式返回 0?

iTa*_*ayb 8 python cython python-3.x

出于某种原因,Cython 在计算结果为 0.5 的数学表达式上返回 0:

print(2 ** (-1))  # prints 0
Run Code Online (Sandbox Code Playgroud)

奇怪的是,混合变量,它会按预期工作:

i = 1
print(2 ** (-i))  # prints 0.5
Run Code Online (Sandbox Code Playgroud)

对于这两种情况,Vanilla CPython 都返回 0.5。我正在编译37m-x86_64-linux-gnu,并language_level设置为3

这是什么巫术?

Dav*_*idW 4

这是因为它使用 C 整数而不是 Python 整数,因此它匹配 C 行为而不是 Python 行为。我相对确定这曾经在某个地方被记录为限制,但我现在找不到它。如果您想将其报告为错误,请转到https://github.com/cython/cython/issues,但我怀疑这是为了兼容性而故意权衡的速度。

代码被翻译为

__Pyx_pow_long(2, -1L)
Run Code Online (Sandbox Code Playgroud)

其中__Pyx_pow_long是 类型的函数static CYTHON_INLINE long __Pyx_pow_long(long b, long e)


解决此问题的最简单方法是将一个/两个数字更改为浮点数

 print(2. ** (-1))
Run Code Online (Sandbox Code Playgroud)

作为对设计选择的一般评论:来自 C 世界的人们通常期望int operator int返回一个int,并且此选项将是最快的。Python 过去曾尝试通过 Python 2 除法行为来做到这一点(但不一致 - power 总是返回浮点数)。

Cython 通常尝试遵循 Python 行为。然而,很多人使用它是为了提高速度,因此他们也尝试回退到快速的、类似 C 的操作,特别是当人们指定类型时(因为这些人想要速度)。我认为这里发生的事情是它能够自动推断类型,因此默认为 C 行为。我怀疑理想情况下它应该区分指定类型和推断的类型。然而,现在开始改变这一点可能也为时已晚。