Search code examples
python-3.xtime-complexitylogarithm

What is the time complexity of math.log2(x) in Python 3?


As the title says, I would like to know what is the time complexity of math.log2(x). I know that it is possible to write such a function in C in O(1) complexity, but I could not find any information about the implementation of this function in Python.


Solution

  • In the CPython implementation of Python log2 is implemented as the following C function, plus a layer above this in C that handles error reporting and handles integers specially but ultimately even in the integer case it is the code below that performs the logarithm.

    The logic is basically to use a standard C log2 function if one is available otherwise compute log2 in terms of log. In any case it is O(1) but with a relatively high constant factor due to all the layers of checks and sanitization.

    /*
       log2: log to base 2.
    
       Uses an algorithm that should:
    
         (a) produce exact results for powers of 2, and
         (b) give a monotonic log2 (for positive finite floats),
             assuming that the system log is monotonic.
    */
    
    static double
    m_log2(double x)
    {
        if (!Py_IS_FINITE(x)) {
            if (Py_IS_NAN(x))
                return x; /* log2(nan) = nan */
            else if (x > 0.0)
                return x; /* log2(+inf) = +inf */
            else {
                errno = EDOM;
                return Py_NAN; /* log2(-inf) = nan, invalid-operation */
            }
        }
    
        if (x > 0.0) {
    #ifdef HAVE_LOG2
            return log2(x);
    #else
            double m;
            int e;
            m = frexp(x, &e);
            /* We want log2(m * 2**e) == log(m) / log(2) + e.  Care is needed when
             * x is just greater than 1.0: in that case e is 1, log(m) is negative,
             * and we get significant cancellation error from the addition of
             * log(m) / log(2) to e.  The slight rewrite of the expression below
             * avoids this problem.
             */
            if (x >= 1.0) {
                return log(2.0 * m) / log(2.0) + (e - 1);
            }
            else {
                return log(m) / log(2.0) + e;
            }
    #endif
        }
        else if (x == 0.0) {
            errno = EDOM;
            return -Py_HUGE_VAL; /* log2(0) = -inf, divide-by-zero */
        }
        else {
            errno = EDOM;
            return Py_NAN; /* log2(-inf) = nan, invalid-operation */
        }
    }