Python 为什么2**100比数学快这么多?
在讨论这个问题时,, 在python中使用Python 为什么2**100比数学快这么多?,python,performance,pow,Python,Performance,Pow,在讨论这个问题时,, 在python中使用math.pow而不是内置的**操作符是没有充分理由的 timeit显示math.pow在所有情况下都比**慢。数学有什么用?有人知道它在哪里有优势吗 我们试图用一些timeit论点说服对方,他是目前为止的赢家;-)——至少以下timeit结果似乎验证了math.pow在所有情况下都比**慢 输出: 0.329639911652 0.0361258983612 0.0364260673523 0.0363788604736 () 我们观察到的差异[1]
math.pow
而不是内置的**
操作符是没有充分理由的
timeit显示math.pow在所有情况下都比**慢。数学有什么用?有人知道它在哪里有优势吗
我们试图用一些timeit论点说服对方,他是目前为止的赢家;-)——至少以下timeit
结果似乎验证了math.pow在所有情况下都比**慢
输出:
0.329639911652
0.0361258983612
0.0364260673523
0.0363788604736
()
我们观察到的差异[1]有简单的解释吗?
[1] math.pow
和**
的性能相差一个数量级
编辑:
- 文本参数而不是标题中的变量
- 明确指出差异大小的脚注
基本上,power操作符在示例中表现得如此出色的原因是Python很可能在编译时使用了power操作符
import dis
dis.dis('3.0 ** 100')
i = 100
dis.dis('3.0 ** i')
这将提供以下输出:
1 0 LOAD_CONST 2 (5.153775207320113e+47)
3 RETURN_VALUE
1 0 LOAD_CONST 0 (3.0)
3 LOAD_NAME 0 (i)
6 BINARY_POWER
7 RETURN_VALUE
您可以在此处看到此运行:
因此,在本例中,您可以看到它实际上没有对power操作符与math.pow
的性能进行公平的比较,因为结果已经预先计算过,然后被缓存。在执行3.0**100
时,不执行任何计算,只返回结果。这比运行时执行的任何求幂操作都要快得多。这最终解释了你的结果
为了进行更公平的比较,您需要使用变量强制计算在运行时进行:
print timeit.timeit("3.0 ** i", setup='i=100')
我尝试在我的计算机上使用python 3.4.1对此进行快速基准测试:
import timeit
trials = 1000000
print("Integer exponent:")
print("pow(2, 100)")
print(timeit.timeit(stmt="pow(2, 100)", number=trials))
print("math.pow(2, 100)")
print(timeit.timeit(stmt="m_pow(2, 100)", setup='import math; m_pow=math.pow', number=trials))
print("2 ** 100")
print(timeit.timeit(stmt="2 ** i", setup='i=100', number=trials))
print("2.0 ** 100")
print(timeit.timeit(stmt="2.0 ** i", setup='i=100', number=trials))
print("Float exponent:")
print("pow(2.0, 100.0)")
print(timeit.timeit(stmt="pow(2.0, 100.0)", number=trials))
print("math.pow(2, 100.0)")
print(timeit.timeit(stmt="m_pow(2, 100.0)", setup='import math; m_pow=math.pow', number=trials))
print("2.0 ** 100.0")
print(timeit.timeit(stmt="2.0 ** i", setup='i=100.0', number=trials))
print("2.01 ** 100.01")
print(timeit.timeit(stmt="2.01 ** i", setup='i=100.01', number=trials))
结果:
Integer exponent:
pow(2, 100)
0.7596459520525322
math.pow(2, 100)
0.5203307256717318
2 ** 100
0.7334983742808263
2.0 ** 100
0.30665244505310607
Float exponent:
pow(2.0, 100.0)
0.26179656874310275
math.pow(2, 100.0)
0.34543158098034743
2.0 ** 100.0
0.1768205988074767
2.01 ** 100.01
0.18460920008178894
所以,看起来转换为float占用了相当多的执行时间
我还为math.pow添加了一个基准。请注意,此函数与内置的pow
函数不同。更多信息,请参见此:这似乎是您链接的一个问题的重复。我相信您给出的链接中的一个答案给出了解释。其中一个会分解每个案例,显示调用的呈现方式。@Lower否。它不是重复的,请查看因子9,而不是类似于1.2的值。@user694733我确信这不是重复的,我在自己添加答案之前阅读了问题和答案,因为您有一些常量,我怀疑幂是在编译时计算的。检查拆卸情况。如果是这样的话,那么你需要像打印timeit.timeit(“2.0**i,setup='i=100.0')
这样的东西来进行公平的比较。这是一个非常好的解释。我终于试着去看“光明”;-)@沃尔夫,是的,这正是这里发生的事情,并解释了巨大的时间差异。嗯,pass
更有效;-)--我试着做一些比较,以使比较公平,所以答案是:它没有那么快的第一印象表明(这只是由于未被注意到的折叠)。但问题的核心仍然是:使用**
总是比使用math.pow
或使用pow
更快。在这种情况下,pow
尤其是math.pow
是否有任何用途(当然,除非您需要对pow
进行模计算)?@Alfe在这里查看,您会发现math.pow
对于浮点变量更快。正如所料。如果你知道一个更好的答案,我很乐意接受;-)
Integer exponent:
pow(2, 100)
0.7596459520525322
math.pow(2, 100)
0.5203307256717318
2 ** 100
0.7334983742808263
2.0 ** 100
0.30665244505310607
Float exponent:
pow(2.0, 100.0)
0.26179656874310275
math.pow(2, 100.0)
0.34543158098034743
2.0 ** 100.0
0.1768205988074767
2.01 ** 100.01
0.18460920008178894