Why is 2**100 so much faster than math.pow(2,100)?

风流意气都作罢 提交于 2019-12-06 01:29:53

问题


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 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?

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")

Output:

0.329639911652
0.0361258983612
0.0364260673523
0.0363788604736

(ideone-shortcut)

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


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

Edits:

  • literal arguments instead of variables in title
  • footnote that explicitly points on the magnitude of difference

回答1:


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')

This gives the following output:

  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

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

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')

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))

results:

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.

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?



来源:https://stackoverflow.com/questions/28563187/why-is-2100-so-much-faster-than-math-pow2-100

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!