为什么 x**4.0
比 x**4
--- 快?我正在使用 CPython 3.5.2。
$ python -m timeit "for x in range(100):" " x**4.0"
10000 loops, best of 3: 24.2 usec per loop
$ python -m timeit "for x in range(100):" " x**4"
10000 loops, best of 3: 30.6 usec per loop
我尝试改变我提高的幂以查看它的作用,例如,如果我将 x 提高到 10 或 16 的幂,它会从 30 跳到 35,但如果我将 10.0 作为浮点数提高,它只是在移动24.1~4左右。
我想这可能与浮点转换和 2 的幂有关,但我真的不知道。
我注意到在这两种情况下 2 的幂都更快,我猜是因为这些计算对于解释器/计算机来说更自然/更容易。但是,有了花车,它几乎不动了。 2.0 => 24.1~4 & 128.0 => 24.1~4
但是 2 => 29 & 128 => 62
TigerhawkT3 指出它不会发生在循环之外。我检查了一下,只有在 底座 升高时才会出现这种情况(据我所见)。对此有什么想法吗?
原文由 arieljannai 发布,翻译遵循 CC BY-SA 4.0 许可协议
Python 3
int
对象是一个完整的对象,旨在支持任意大小;由于这个事实,它们 在 C 级别上被这样处理(请参阅如何将所有变量声明为PyLongObject *
输入long_pow
)。这也使它们的求幂变得更加 棘手 和 _乏味_,因为您需要使用ob_digit
数组来表示它的值来执行它。 ( 勇敢者的来源。——请参阅: 了解 Python 中大整数的内存分配,了解 更多关于PyLongObject
s 的信息。)相反,Python
float
对象 可以转换 为 Cdouble
类型(通过使用PyFloat_AsDouble
)并且可以 使用这些原生类型 执行操作。 _这很棒_,因为在检查了相关的边缘情况后,它允许 Python 使用平台的pow
( C 的pow
)来处理实际的取幂:其中
iv
double
iw
PyFloatObject
之前的事实 也解释 了 Python 2 和 3 之间的差异,所以我想我也应该解决这个评论,因为它很有趣。
在 Python 2 中,您使用的是旧的
int
不同于 Python 3 中的int
对象的对象(所有int
PyLongObject
的对象。---
类型)。在 Python 2 中,有一个区别取决于对象的值(或者,如果您使用后缀L/l
):<type 'int'>
你在这里看到 _做同样的事情float
s 做_,它被安全地转换成 Clong
int_pow
它上执行指数时---
还提示编译器在可以的情况下将它们放入寄存器中,这样 可能会 有所作为):这样可以获得良好的速度增益。
To see how
<type 'long'>
s are in comparison to<type 'int'>
s, if you wrapped thex
name in along
call in Python 2 (本质上是强制它使用long_pow
就像在 Python 3 中一样),速度增益消失了:请注意,尽管一个片段将
int
转换为long
而另一个片段没有(正如@pydsinger 指出的那样),但这个转换并不是减速背后的贡献力量。long_pow
的实施是。 (仅使用long(x)
为语句计时以查看)。这是 CPython 的窥孔优化器,为您折叠常量。在任何一种情况下,您都会得到相同的精确时间,因为没有实际计算来查找求幂的结果,仅加载值:
Identical byte-code is generated for
'4 ** 4.'
with the only difference being that theLOAD_CONST
loads the float256.0
instead of the int256
:所以时间是一致的。
*以上所有仅适用于 CPython,Python 的参考实现。其他实现可能会有不同的表现。