Python 为什么2**100比数学快这么多?

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]

在讨论这个问题时,, 在python中使用
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