90

Which one is more efficient using math.pow or the ** operator? When should I use one over the other?

So far I know that x**y can return an int or a float if you use a decimal the function pow will return a float

import math

print( math.pow(10, 2) )

print( 10. ** 2 )
ctrl-alt-delor
  • 7,506
  • 5
  • 40
  • 52
user3084006
  • 5,344
  • 11
  • 32
  • 41
  • 7
    Why not `timeit` to find out? – mgilson Jan 07 '14 at 10:53
  • 4
    `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? – Alfe Jan 07 '14 at 11:09
  • 1
    @Alfe how did you measure, or do I misunderstand your `in all cases`? I [see cases](http://stackoverflow.com/a/28539821/2932052) where `math.pow` is much faster. – Wolf Feb 16 '15 at 11:21
  • 1
    @Wolf, Do you? Your link points to a comparison of `pow` with `math.pow`, but I'm talking about a comparison of `math.pow` with the `**` operator. Your comparison there can be completed by adding that third version, then `**` again beats every other option: `import timeit; print timeit.timeit("math.pow(2, 100)",setup='import math'), timeit.timeit("pow(2, 100)"), timeit.timeit("2 ** 100")` → `0.170357942581 1.00546097755 0.013473033905`. – Alfe Feb 17 '15 at 11:22
  • But I have to admit that the results are not exactly the same. `math.pow` _always_ returns a `float` (also for `int` input) while `**` returns the type of its input (well, mixed input results in `float`). But that's still no good reason to use `math.pow`, IMHO. – Alfe Feb 17 '15 at 12:20
  • @Alfe [WOW](http://ideone.com/fDZeTZ) thanks for pointing out this detail. Is there a simple explanation (besides referring the source code)? ...maybe a good question for SO ;-) ? – Wolf Feb 17 '15 at 13:10
  • @Alfe even if *an* answer is found to the question [Why is a**b so much faster than math.pow(a,b)?](http://stackoverflow.com/q/28563187/2932052) - and I really don't like to import math for pow - I'm not sure if there isn't something left. And *your* question (*`What is math.pow() good for anyway?`*) seems to be unanswered yet. Anyway, thanks a lot for your time :-) – Wolf Feb 17 '15 at 16:36
  • Still investigating this, but answers here seem to be incomplete. I was doing some somewhat large cryptographic calculations, and while `4926601444670 ** 4235309647073 % 6000029000033` crashes the interpreter, `pow(4926601444670 , 4235309647073, 6000029000033)` is instantaneous. – temporary_user_name May 01 '16 at 07:11
  • Yeah, see this http://stackoverflow.com/questions/14133806/why-is-powa-d-n-so-much-faster-than-ad-n – temporary_user_name May 01 '16 at 07:13

7 Answers7

138

Using the power operator ** will be faster as it won’t have the overhead of a function call. You can see this if you disassemble the Python code:

>>> dis.dis('7. ** i')
  1           0 LOAD_CONST               0 (7.0) 
              3 LOAD_NAME                0 (i) 
              6 BINARY_POWER         
              7 RETURN_VALUE         
>>> dis.dis('pow(7., i)')
  1           0 LOAD_NAME                0 (pow) 
              3 LOAD_CONST               0 (7.0) 
              6 LOAD_NAME                1 (i) 
              9 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
             12 RETURN_VALUE         
>>> dis.dis('math.pow(7, i)')
  1           0 LOAD_NAME                0 (math) 
              3 LOAD_ATTR                1 (pow) 
              6 LOAD_CONST               0 (7) 
              9 LOAD_NAME                2 (i) 
             12 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
             15 RETURN_VALUE         

Note that I’m using a variable i as the exponent here because constant expressions like 7. ** 5 are actually evaluated at compile time.

Now, in practice, this difference does not matter that much, as you can see when timing it:

>>> from timeit import timeit
>>> timeit('7. ** i', setup='i = 5')
0.2894785532627111
>>> timeit('pow(7., i)', setup='i = 5')
0.41218495570683444
>>> timeit('math.pow(7, i)', setup='import math; i = 5')
0.5655053168791255

So, while pow and math.pow are about twice as slow, they are still fast enough to not care much. Unless you can actually identify the exponentiation as a bottleneck, there won’t be a reason to choose one method over the other if clarity decreases. This especially applies since pow offers an integrated modulo operation for example.


Alfe asked a good question in the comments above:

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?

The big difference of math.pow to both the builtin pow and the power operator ** is that it always uses float semantics. So if you, for some reason, want to make sure you get a float as a result back, then math.pow will ensure this property.

Let’s think of an example: We have two numbers, i and j, and have no idea if they are floats or integers. But we want to have a float result of i^j. So what options do we have?

  • We can convert at least one of the arguments to a float and then do i ** j.
  • We can do i ** j and convert the result to a float (float exponentation is automatically used when either i or j are floats, so the result is the same).
  • We can use math.pow.

So, let’s test this:

>>> timeit('float(i) ** j', setup='i, j = 7, 5')
0.7610865891750791
>>> timeit('i ** float(j)', setup='i, j = 7, 5')
0.7930400942188385
>>> timeit('float(i ** j)', setup='i, j = 7, 5')
0.8946636625872202
>>> timeit('math.pow(i, j)', setup='import math; i, j = 7, 5')
0.5699394063529439

As you can see, math.pow is actually faster! And if you think about it, the overhead from the function call is also gone now, because in all the other alternatives we have to call float().


In addition, it might be worth to note that the behavior of ** and pow can be overridden by implementing the special __pow__ (and __rpow__) method for custom types. So if you don’t want that (for whatever reason), using math.pow won’t do that.

poke
  • 369,085
  • 72
  • 557
  • 602
  • You got +1 for " the behavior of ** and pow can be overridden": If writting module, I am sure it very matters to prevent surprises comming from the user environment.... – Xerix Feb 25 '21 at 09:44
34

The pow() function will allow you to add a third argument as a modulus.

For example: I was recently faced with a memory error when doing

2**23375247598357347582 % 23375247598357347583

Instead I did:

pow(2, 23375247598357347582, 23375247598357347583)

This returns in mere milliseconds instead of the massive amount of time and memory that the plain exponent takes. So, when dealing with large numbers and parallel modulus, pow() is more efficient, however when dealing with smaller numbers without modulus, ** is more efficient.

bravoalpha90
  • 413
  • 4
  • 5
  • The question isn't asking about built-in [`pow`](https://docs.python.org/3/library/functions.html#pow). It's asking about `math.pow(x, y)` vs `x ** y`. – wim Oct 09 '22 at 13:56
  • https://stackoverflow.com/questions/14133806/why-is-powa-d-n-so-much-faster-than-ad-n, relevant here, was cited in comments above. – sancho.s ReinstateMonicaCellio Jan 06 '23 at 08:05
7

Just for the protocol: The ** operator is equivalent to the two-argument version of the built-in pow function, the pow function accepts an optional third argument (modulus) if the first two arguments are integers.

So, if you intend to calculate remainders from powers, use the built-in function. The math.pow will give you false results for arguments of reasonable size:

import math

base = 13
exp = 100
mod = 2
print math.pow(base, exp) % mod
print pow(base, exp, mod)

When I ran this, I got 0.0 in the first case which obviously cannot be true, because 13 is odd (and therefore all of it's integral powers). The math.pow version uses the limited accuracy of the IEEE-754 Double precision (52 bits mantissa, slightly less than 16 decimal places) which causes an error here.

For sake of fairness, we must say, math.pow can also be faster:

>>> import timeit
>>> min(timeit.repeat("pow(1.1, 9.9)", number=2000000, repeat=5))
0.3063715160001266
>>> min(timeit.repeat("math.pow(1.1, 9.9)", setup="import math", number=2000000, repeat=5))
0.2647279420000359

The math.pow function had (and still has) its strength in engineering applications, but for number theoretical applications, you should use the built-in pow function.


Some online examples


Update (inevitable correction):
I removed the timing comparison of math.pow(2,100) and pow(2,100) since math.pow gives a wrong result whereas, for example, the comparison between pow(2,50) and math.pow(2,50) would have been fair (although not a realistic use of the math-module function). I added a better one and also the details that cause the limitation of math.pow.

Wolf
  • 9,679
  • 7
  • 62
  • 108
6

** is indeed faster then math.pow(), but if you want a simple quadratic function like in your example it is even faster to use a product.

10.*10.

will be faster then

10.**2

The difference is not big and not noticable with one operation (using timeit), but with a large number of operations it can be significant.

KDhoore
  • 69
  • 1
  • 3
4

Well, they are for different tasks, really.

Use pow (equivalent to x ** y with two arguments) when you want integer arithmetic.

And use math.pow if either argument is float, and you want float output.

For a discussion on the differences between pow and math.pow, see this question.

Community
  • 1
  • 1
wim
  • 338,267
  • 99
  • 616
  • 750
0

operator ** (same as pow()) can be used to calculate very large integer number.

>>> 2 ** 12345
164171010688258216356020741663906501410127235530735881272116103087925094171390144280159034536439457734870419127140401667195510331085657185332721089236401193044493457116299768844344303479235489462...

>>> math.pow(2, 12345)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: math range error
Zhaolin Feng
  • 428
  • 4
  • 8
0

For small powers, like 2, I prefer to just multiply the base:

Use x*x instead of x**2 or pow(x, 2).

I haven't timed it, but I'd bet the multiplier is as fast as either the exponential operator or the pow function.

duffymo
  • 305,152
  • 44
  • 369
  • 561