为什么 2**100 比 math.pow(2,100) 快这么多?
Why is 2**100 so much faster than math.pow(2,100)?
在讨论问题Exponentials in python x.**y vs math.pow(x, y)时,
Alfe stated 没有充分的理由在 python.
中使用 math.pow
而不是内置的 **
运算符
timeit shows that math.pow is slower than ** in all cases. What is math.pow() good for anyway? Has anybody an idea where it can be of any advantage then?
我们试图用一些 timeit
论点说服对方,到目前为止他是赢家 ;-) -- 至少以下 timeit
结果似乎证实了 math.pow is slower than ** in all cases
.
import timeit
print timeit.timeit("math.pow(2, 100)",setup='import math')
print timeit.timeit("2.0 ** 100.0")
print timeit.timeit("2 ** 100")
print timeit.timeit("2.01 ** 100.01")
输出:
0.329639911652
0.0361258983612
0.0364260673523
0.0363788604736
我们观察到的差异[1]有简单的解释吗?
[1]math.pow
和**
的性能相差一个数量级
编辑:
- 文字参数而不是标题中的变量
- 明确指出差异幅度的脚注
从根本上说,幂运算符在您的示例中看起来表现得很好的原因是因为 Python 在编译时很可能 folded the constant。
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
您可以在此处查看 运行:http://ideone.com/5Ari8o
所以在这种情况下,您可以看到它实际上并没有对幂运算符与 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
所以看起来转换为浮点数占用了相当多的执行时间。
我还为 math.pow
添加了一个基准,请注意,此功能与内置功能不同 pow
更多信息请参见:Difference between the built-in pow() and math.pow() for floats, in Python?
在讨论问题Exponentials in python x.**y vs math.pow(x, y)时, Alfe stated 没有充分的理由在 python.
中使用math.pow
而不是内置的 **
运算符
timeit shows that math.pow is slower than ** in all cases. What is math.pow() good for anyway? Has anybody an idea where it can be of any advantage then?
我们试图用一些 timeit
论点说服对方,到目前为止他是赢家 ;-) -- 至少以下 timeit
结果似乎证实了 math.pow is slower than ** in all cases
.
import timeit
print timeit.timeit("math.pow(2, 100)",setup='import math')
print timeit.timeit("2.0 ** 100.0")
print timeit.timeit("2 ** 100")
print timeit.timeit("2.01 ** 100.01")
输出:
0.329639911652
0.0361258983612
0.0364260673523
0.0363788604736
我们观察到的差异[1]有简单的解释吗?
[1]math.pow
和**
的性能相差一个数量级
编辑:
- 文字参数而不是标题中的变量
- 明确指出差异幅度的脚注
从根本上说,幂运算符在您的示例中看起来表现得很好的原因是因为 Python 在编译时很可能 folded the constant。
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
您可以在此处查看 运行:http://ideone.com/5Ari8o
所以在这种情况下,您可以看到它实际上并没有对幂运算符与 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
所以看起来转换为浮点数占用了相当多的执行时间。
我还为 math.pow
添加了一个基准,请注意,此功能与内置功能不同 pow
更多信息请参见:Difference between the built-in pow() and math.pow() for floats, in Python?