Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 241
Mr. T Avatar asked Dec 18 '17 16:12

Mr. T


2 Answers

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.

like image 161
internet_user Avatar answered Sep 22 '22 11:09

internet_user


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
like image 32
s-m-e Avatar answered Sep 18 '22 11:09

s-m-e