为什么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,但如果我把x的力量提高到10.0作为一个浮点数,它只会在24.1~4左右移动。
我想这可能与浮点数转换和2的幂有关,但我不太清楚。
我注意到在这两种情况下,2的幂更快,我猜是因为这些计算对于解释器/计算机来说更为原生/简单。不过,有了漂浮物,它几乎不动了。2.0 => 24.1~4 & 128.0 => 24.1~4
但是2 => 29 & 128 => 62
因为一个是正确的,另一个是近似。
Python 3
int
对象是一个成熟的对象,设计用于支持任意大小;因此,它们是handled as such on the C level(请参见如何在long_pow
中将所有变量声明为PyLongObject *
类型)。这也使得它们的指数化变得更加复杂,而且非常乏味,因为您需要处理它用来表示其值的ob_digit
数组。(Source for the brave.——有关PyLongObject
s的详细信息,请参见:Understanding memory allocation for large integers in Python。)Python} ),并且可以执行操作using those native types。这很好,因为在检查了相关的边情况之后,它允许Python use the platforms' ^{} (C's ^{}, that is )处理实际的指数运算:
float
对象,相反,可以转换为Cdouble
类型(通过使用^{其中
iv
和iw
是我们最初的PyFloatObject
s作为Cdouble
s前面的事实也解释了Python 2和3之间的差异,所以,我想我也会处理这个注释,因为它很有趣。
在Python2中,您使用的是与Python3中的
int
对象不同的旧int
对象(3.x中的所有int
对象都是PyLongObject
类型)。在Python 2中,有一个区别取决于对象的值(或者,如果使用后缀L/l
):你在这里看到的
<type 'int'>
做了同样的事情float
s做了,它被安全地转换成一个Clong
when exponentiation is performed on it(如果编译器可以的话,int_pow
还提示编译器将它们放入一个寄存器中,这样就可以产生不同的效果):这样可以获得良好的速度增益。
要查看与
<type 'int'>
s相比<type 'long'>
s有多慢,如果在Python 2中将x
名称包装在long
调用中(本质上强制它使用long_pow
,如Python 3中所示),速度增益将消失:请注意,尽管一个片段将
int
转换为long
,而另一个片段则没有(正如@pydsinger指出的那样),但这个类型转换并不是导致减速的原因。long_pow
的实现是。(仅使用long(x)
计时语句以查看)。这是CPython的窥视孔优化器,为您折叠常量。无论哪种情况,都会得到相同的精确计时,因为没有实际的计算来找到指数运算的结果,只加载值:
为
'4 ** 4.'
生成相同的字节码,唯一的区别是LOAD_CONST
加载浮点256.0
,而不是int256
:所以时间是一样的。
*以上所有内容仅适用于Python的参考实现CPython。其他实现可能会有不同的表现。
如果我们看一下字节码,我们可以看到表达式是完全相同的。唯一的区别是一种常量类型,它将是
BINARY_POWER
的参数。所以这肯定是由于int
被转换成一个下线的浮点数。更新:让我们看看CPython源代码中的Objects/abstract.c:
PyNumber_Power
调用ternary_op
,太长,无法粘贴在此处,因此here's the link。它调用
x
的nb_power
槽,将y
作为参数传递。最后,在Objects/floatobject.c的第686行的
float_pow()
中,我们看到参数在实际操作之前被转换为Cdouble
:相关问题 更多 >
编程相关推荐