Mr. T
Mr. T

Reputation: 12410

Does the base for logarithmic calculations in Python influence the speed?

I have to use a lot of logarithmic calculations in one program. In terms of the logarithmic base, the procedure is not specific. I was wondering, if any base n (2? 10? e?) is faster in the Python 3.5 math module than others, because maybe under the hood all other bases a are transformed into log_a(x) = log_n(x)/log_n(a). Or does the choice of the base not influence the speed of the calculation, because all bases are implemented in the same way using a C library?

Upvotes: 7

Views: 1344

Answers (2)

internet_user
internet_user

Reputation: 3279

In CPython, math.log is base independent, but platform dependent. From the C source for the math module, on lines 1940-1961, the code for math.log is shown.

math_log_impl(PyObject *module, PyObject *x, int group_right_1,
          PyObject *base)
/*[clinic end generated code: output=7b5a39e526b73fc9 input=0f62d5726cbfebbd]*/

{
    PyObject *num, *den;
    PyObject *ans;

    num = loghelper(x, m_log, "log"); // uses stdlib log
    if (num == NULL || base == NULL)
        return num;

    den = loghelper(base, m_log, "log"); // uses stdlib log
    if (den == NULL) {
        Py_DECREF(num);
        return NULL;
    }

    ans = PyNumber_TrueDivide(num, den);
    Py_DECREF(num);
    Py_DECREF(den);
    return ans;
}

This, no matter what, calculates the natural log of the number and base, so unless the C log function has a special check for e, it will run at the same speed.

This source also explains the other answer's log2 and log10 being faster than log. They are implemented using the standard library log2 and log10 functions respectively, which will be faster. These functions, however, are defined differently depending on the platform.

Note: I am not very familiar with C so I may be wrong here.

Upvotes: 5

s-m-e
s-m-e

Reputation: 3721

Interesting question. I did some "good old" field test (CPython 3.6.2 on Linux, x86_64, i7-3740QM CPU - Python interpreter compiled with all optimizations available for this CPU turned ON).

>>> math.log10(3)
0.47712125471966244
>>> math.log(3, 10)
0.47712125471966244
>>> timeit.timeit('math.log(3, 10)', setup = 'import math')
0.2496643289923668
>>> timeit.timeit('math.log10(3)', setup = 'import math')
0.14756392200069968

Log10 is clearly faster than log(n, 10).

>>> math.log2(3.0)
1.584962500721156
>>> math.log(3.0, 2.0)
1.5849625007211563
>>> timeit.timeit('math.log2(3.0)', setup = 'import math')
0.16744944200036116
>>> timeit.timeit('math.log(3.0, 2.0)', setup = 'import math')
0.22228705599263776

Log2 is also clearly faster than log(n, 2). Btw, either way, floats and ints are equally fast.

With numpy, the picture is different. It kind of does not matter what you do:

>>> timeit.timeit('numpy.log(numpy.arange(1, 10))', setup = 'import numpy')
2.725074506000965
>>> timeit.timeit('numpy.log10(numpy.arange(1, 10))', setup = 'import numpy')
2.613872367001022
>>> timeit.timeit('numpy.log2(numpy.arange(1, 10))', setup = 'import numpy')
2.58251854799164

Upvotes: 2

Related Questions