2

I noticed something peculiar: for non-trivial exponents (so not 1, 2, and 0.5), numpy's power function seems to be slower than calculating the same thing through logarithms.

Consider the following timing code:

import timeit
import numpy as np

two_thirds = (2.0 / 3.0)

def simple(x):
    return x**two_thirds

def numpy_power(x):
    return np.power(x, two_thirds)

def numpy_exp_log(x):
    return np.exp(np.log(x) * two_thirds)


arr = np.random.rand(100)
min(timeit.Timer("simple(arr)", setup="from __main__ import arr, simple, two_thirds").repeat(10, 10000))
min(timeit.Timer("numpy_power(arr)", setup="from __main__ import arr, numpy_power, two_thirds").repeat(10, 10000))
min(timeit.Timer("numpy_exp_log(arr)", setup="from __main__ import arr, numpy_exp_log, two_thirds").repeat(10, 10000))

According to these timings, my numpy_exp_log function takes only about 65% of the time of the other two functions. They return the same values (modulo floating point rounding errors, which don't matter all that much to me). This seems really peculiar to me.

Is it feasible that my function is only faster than numpy's power on my hardware, and other hardware might not display such a difference? How much of the computation is shipped off to hardware-specific instructions? Can I expect this difference to occur on pretty much any computer running the same version of Python/Numpy? (Python 3.6.5, Numpy 1.16.1)

acdr
  • 4,538
  • 2
  • 19
  • 45
  • `exp` should be faster than `pow` in general -- see https://stackoverflow.com/questions/17891595/pow-vs-exp-performance (JS, but the principle is the same). – tzaman Jan 17 '20 at 14:50
  • @tzaman: I'm aware that that's the case in general. But here, I'm throwing a multiplication and a *logarithm* on top. Especially the latter, I would have expected to be significantly slower. – acdr Jan 17 '20 at 14:55
  • Now try it with, for example, `arr = np.random.exponential(scale=1000, size=10000) `. – Warren Weckesser Jan 17 '20 at 15:34
  • @WarrenWeckesser: Not sure if this matches what you got, but with such arrays, my function's faster by *even more*. – acdr Jan 17 '20 at 15:39
  • Yes, that's what I observed too. – Warren Weckesser Jan 17 '20 at 15:40
  • @acdr if you read the linked question, you'll see that this is the exact case being discussed. Exp and log tend to have optimized implementations or hardware instructions (including for things like `a * log b`) which will beat out a general `pow`, even when put together. – tzaman Jan 17 '20 at 16:20

0 Answers0