In other words, what exists behind the two asterisks? Is it simply multiplying the number x times or something else?

As a follow-up question, is it better to write 2**3 or 2*2*2. I'm asking because I've heard that in C++ it's better to not use pow() for simple calculations, since it calls a function.

5

5 Answers

If you're interested in the internals, I'd disassemble the instruction to get the CPython bytecode it maps to. Using Python3:

»»» def test(): return 2**3 ...: »»» dis.dis(test) 2 0 LOAD_CONST 3 (8) 3 RETURN_VALUE 

OK, so that seems to have done the calculation right on entry, and stored the result. You get exactly the same CPython bytecode for 2*2*2 (feel free to try it). So, for the expressions that evaluate to a constant, you get the same result and it doesn't matter.

What if you want the power of a variable?

Now you get two different bits of bytecode:

»»» def test(n): return n ** 3 »»» dis.dis(test) 2 0 LOAD_FAST 0 (n) 3 LOAD_CONST 1 (3) 6 BINARY_POWER 7 RETURN_VALUE 

vs.

»»» def test(n): return n * 2 * 2 ....: »»» dis.dis(test) 2 0 LOAD_FAST 0 (n) 3 LOAD_CONST 1 (2) 6 BINARY_MULTIPLY 7 LOAD_CONST 1 (2) 10 BINARY_MULTIPLY 11 RETURN_VALUE 

Now the question is of course, is the BINARY_MULTIPLY quicker than the BINARY_POWER operation?

The best way to try that is to use timeit. I'll use the IPython %timeit magic. Here's the output for multiplication:

%timeit test(100) The slowest run took 15.52 times longer than the fastest. This could mean that an intermediate result is being cached 10000000 loops, best of 3: 163 ns per loop 

and for power

The slowest run took 5.44 times longer than the fastest. This could mean that an intermediate result is being cached 1000000 loops, best of 3: 473 ns per loop 

You may wish to repeat this for representative inputs, but empirically it looks like the multiplication is quicker (but note the mentioned caveat about the variance in the output).

If you want further internals, I'd suggest digging into the CPython code.

4

While the second one is little bit faster for numbers, the advantage is very low compared to the first: readability. If you are going for time, and you are pressured to make such optimizations, then python probably is not the language you should use.

Note: for values other than numbers:

a ** b translates to

a.__pow__(b) 

whereas a * a * a is a call to

a.__mul__(a.__mul__(a)) 

Test Code:

import time s = time.time() for x in xrange(1,1000000): x**5 print "done in ", time.time() - s s = time.time() for x in xrange(1,1000000): x*x*x*x*x print "done in ", time.time() - s 

For my machine it yields:

done in 0.975429058075 done in 0.260419845581 [Finished in 1.2s] 

If you ask frankly, multiplication is a bit faster.

>>timeit.timeit('[i*i*i*i for i in range(100)]', number=10000) 0.262529843304 >>timeit.timeit('[i**4 for i in range(100)]', number=10000) 0.31143438383 

But, speed isn't the only thing to consider when you will choose one from two options. From example, what is easier while computing 2 to the power 20? Simply writing 2**20 or using for loop that will iterate 20 times and do some multiplication task?

The ** operator will, internally, use an iterative function (same semantics as built-in pow() (Python docs), which likely means it just calls that function anyway).

Therefore, if you know the power and can hardcode it, using 2*2*2 would likely be a little faster than 2**3. This has a little to do with the function, but I believe the main performance issue is that it will use a loop.


Note that it's still quite silly to replace more readable code for less readable code when it's something as simple as 2**3, the performance gain is minimal at best.

1

From the docs:

The power operator binds more tightly than unary operators on its left; it binds less tightly than unary operators on its right. The syntax is:

power ::= primary ["**" u_expr] 

Thus, in an unparenthesized sequence of power and unary operators, the operators are evaluated from right to left (this does not constrain the evaluation order for the operands): -1**2 results in -1.

The power operator has the same semantics as the built-in pow() function, when called with two arguments: it yields its left argument raised to the power of its right argument.

This means that, in Python: 2**2**3 is evaluated as 2**(2**3) = 2**8 = 256.

In mathematics, stacked exponents are applied from the top down. If it were not done this way you would just get multiplication of exponents:

(((2**3)**4)**5) = 2**(3*4*5) 

It might be a little faster just to do the multiplication, but much less readable.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy