4

So I've been constantly seeing people write code, when they wish to see the squared version of a given value, they will write out x*x instead of x**2. Is there that big of an efficiency overlap between these two points, that the given function, in python, is not just used, or is it just a stylistic point? I would much rather use the ** operator, but if it will cause a huge misstep, should I be doing the operation a billion times, excessive I know, I'd kind of like to know. Also if I am mistaken in the order of magnitude for operations that one takes over the other I'd also like to be corrected on that. ie if ** is more efficient than x*x then I'd like to know why as well.

L.P.
  • 406
  • 5
  • 17
  • 1
    I guess people use `x*x` instead of `x**2`, because it works in all languages, whereas `x**2` works not in Java / C / C++. So I guess the reason is ignorance for most examples. I'm curious to get to know if there is an efficiency difference / numeric difference, though. – Martin Thoma Oct 17 '15 at 17:04

2 Answers2

6

I do not agree with g.d.d.c, multiplication is much faster !

"""Evaluating the difference in execution time between n*n and n**2"""

from time import time

n = 2
t = time()
for i in range(5000000):
    n**2
print("Time for n**2:\t%0.3f" % (time()-t))
t = time()
for i in range(5000000):
    n*n
print("Time for n*n:\t%0.3f" % (time()-t))


def test(n):
    """
    Difference in execution time between n*n and n**2
    within function scope.
    """
    t = time()
    for i in range(5000000):
        n**2
    print("Time for n**2:\t%0.3f" % (time()-t))
    t = time()
    for i in range(5000000):
        n*n
    print("Time for n*n:\t%0.3f" % (time()-t))

test(n)

Results :

Time for n**2: 2.324496030807495
Time for n*n:  0.5879969596862793
Time for n**2: 2.0771241188049316
Time for n*n:  0.2894318103790283

You can see that multiplication is about 4 times faster outside of a function, and 7 times faster in the function. I cannot explain the difference between those two tests, and I am not sure about the difference between n*n and n**2, but it might be related with the fact that Python is an interpreted language, and the processing of the latter takes more time, even if the processor operations are very similar, as g.d.d.c demonstrates.

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
Labo
  • 2,482
  • 2
  • 18
  • 38
  • 1
    Why does it make a difference (and such a huge one!) if it is in a function or outside of a function? – Martin Thoma Oct 17 '15 at 17:12
  • 1
    @moose: Most likely because global variable lookup is a dict lookup, while local variable lookup is indexing into an array. – user2357112 Oct 17 '15 at 17:14
  • 1
    Now I'm a bit more confused, I see that it does in fact take into account the massive speed difference, which kind of denotes my initial point. I didn't think it would be that large of a difference though, or that it would cause a differentiation between being in the scope of a function or out of it. Such a strange language sometimes. – L.P. Oct 17 '15 at 17:18
  • @user2357112 what you say is very interesting, could you explain further please ? I though that locals() returns a dict as well as globals()… – Labo Oct 17 '15 at 17:18
  • 4
    Also, it looks like you timed this on Python 3, while the other guy timed on Python 2. Python 3's bignum exponentiation performs a lot worse than Python 2's exponentiation for this case; on Python 2, the timings are nearly identical for `n**2` and `n*n`, as in the other answer. – user2357112 Oct 17 '15 at 17:24
  • @Labo: `locals()` returns a dict, but Python doesn't actually use the dict for local variable lookup. That's one of the reasons the docs say not to modify the dict; it won't affect the values of local variables. – user2357112 Oct 17 '15 at 17:33
  • Incidentally, what Python 3 version are you on? My test on [ideone](http://ideone.com/qgVqIH), for which Python 3 is Python 3.4, showed a substantial improvement in exponentiation performance relative to multiplication. – user2357112 Oct 17 '15 at 17:37
  • Python 3.4.3 but 3 or 4 is almost the same… – Labo Oct 17 '15 at 17:56
  • +1 for the code; but you should also make the switched experiment: Just switch the code blocks of `n*n` and `n**2`. Especially for the "global experiment", you will note that this makes a difference. – Martin Thoma Oct 17 '15 at 23:45
2

Realistically, the two are probably very similar in total cost:

>>> def s1(x):
...   return x * x
...
>>>
>>> def s2(x):
...   return x ** 2
...
>>>
>>> from dis import dis
>>>
>>> dis(s1)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                0 (x)
              6 BINARY_MULTIPLY
              7 RETURN_VALUE
>>> dis(s2)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (2)
              6 BINARY_POWER
              7 RETURN_VALUE
>>>

I think you're probably prematurely optimizing, even for millions or billions of iterations. Unless you've identified this as a bottleneck, just use what's most idiomatic for you.

And, for completeness, the timeit results:

>>> timeit.Timer("s1(10)", 'from __main__ import s1').timeit(100000)
0.0186597650628606
>>> timeit.Timer("s2(10)", 'from __main__ import s2').timeit(100000)
0.018789616358585448

Which appears to show that x * x is ever so slightly faster in 100000 iterations.

g.d.d.c
  • 46,865
  • 9
  • 101
  • 111
  • So it is in itself just a style concept. I always thought that it was just something along the lines of the pow() function in c, since it made a function call I saw the need in that language, but in python since it's built in. I just don't see why not to use it. It's a bit more expressive in my view than then other, as long as the operator is known, and understood. Thank you for that snippet though. – L.P. Oct 17 '15 at 17:07
  • For 10e6 it is that value, but would it grow exponentially in time complexity, or constantly? I know in the grand scheme this would matter just a bit less but doing Project Euler Problems, to teach myself the Python language, and time, even a quarter second, is messing with a me a bit. – L.P. Oct 17 '15 at 17:17
  • 2
    Nah. Exponentiation is **much** slower than multiplication on conventional CPUs. Your benchmark doesn’t show this because the time is dominated by the cost of the function call (I’m guessing) or other dynamic Python shenanigans. In compiled languages, the difference is drastic. Even in Python I could imagine it making a big difference in a tight loop without function call, but I didn’t benchmark. Anyway, this is (unfortunately) far from a premature optimisation for many applications. – Konrad Rudolph Oct 17 '15 at 17:17
  • 1
    @KonradRudolph: It's not a CPU thing; Python int exponentiation doesn't invoke any CPU exponentiation instructions. It's all software. In Python 2, even if you strip out the function call, the difference is about 6% due to all the other overhead; in Python 3, [the difference is about a factor of 3](http://ideone.com/qgVqIH), since the bignum exponentiation code doesn't handle things as well. – user2357112 Oct 17 '15 at 17:30
  • @user2357112 I don’t see how this would make things better. Implementing exponentiation in software would make this *even slower* by comparison to multiplication. Your benchmark is insufficient to show this difference because the operations are way too fast, and the precision of the timer comparatively too low. – Konrad Rudolph Oct 17 '15 at 19:22