为什么 2**100 比 math.pow(2,100) 快这么多? [英] Why is 2**100 so much faster than math.pow(2,100)?

查看:87
本文介绍了为什么 2**100 比 math.pow(2,100) 快这么多?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在讨论 python 中的指数 x.**y vs math.pow(x, y) 时,Alfe 表示使用 math.pow 而不是 Python 中的内置 ** 运算符.

When discussing the question Exponentials in python x.**y vs math.pow(x, y), Alfe stated that there would be no good reason for using math.pow instead of the builtin ** operator in python.

timeit 显示 math.pow 在所有情况下都比 ** 慢.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 在所有情况下都比 ** 慢.

We tried to convince each other with some timeit arguments an he is the winner so far ;-) -- At least the following timeit results, seem to verify that 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

(ideone-shortcut)

对于我们观察到的差异[1]是否有一个简单的解释?

Is there a simple explanation for the difference[1] we observe?

[1] math.pow** 的性能相差一个数量级.

[1] The performances of math.pow and ** differ by one order of magnitude.

  • 文字参数而不是标题中的变量
  • 明确指出差异幅度的脚注

推荐答案

幂运算符在您的示例中表现如此出色的根本原因是因为 Python 很可能具有 在编译时折叠常量.

Essentially the reason that the power operator looks like it's doing so well in your examples is because Python has most likely folded the constant at compile time.

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

You can see this run here: http://ideone.com/5Ari8o

因此,在这种情况下,您可以看到它实际上并没有对幂运算符与 math.pow 的性能进行公平的比较,因为结果已预先计算然后缓存.当您制作 3.0 ** 100 时,没有执行任何计算,只是返回结果.这比在运行时执行的任何幂运算要快得多.这最终解释了您的结果.

So in this case you can see it's not actually doing a fair comparison of the performance of the power operator vs math.pow because the result has been precomputed then cached. When you are making the 3.0 ** 100 there's no computation performed, the result is just being returned. This you would expect to be much faster than any exponentiation operation performed at runtime. This is ultimately what explains your results.

为了更公平的比较,您需要使用变量强制在运行时进行计算:

For a more fair comparison you need to force the computation to occur at runtime by using a variable:

print timeit.timeit("3.0 ** i", setup='i=100')

我尝试在我的计算机上使用 python 3.4.1 对此进行快速基准测试:

I tried making a quick benchmark for this using the python 3.4.1 on my computer:

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

所以看起来转换为浮点数会占用相当多的执行时间.

So it looks like the conversion to a float eats up a fair amount of the execution time.

我还为 math.pow 添加了一个基准,请注意此函数与内置的 pow 不同,请参阅此内容以了解更多信息:内置 pow() 和 math.pow 之间的区别() 用于浮点数,在 Python 中?

I also added a benchmark for math.pow note that this function is not the same as the builtin pow see this for more: Difference between the built-in pow() and math.pow() for floats, in Python?

这篇关于为什么 2**100 比 math.pow(2,100) 快这么多?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆