Reputation: 140256
from math import log,sqrt
import sys
n = 760 ** 890
print(log(n))
I get a valid result.
Now change log
by sqrt
and you get (as expected):
OverflowError: int too large to convert to float
So I suppose there's a trick for integer arguments in log
function, using integer logarithms but I didn't find that in the documentation. There's just this:
math.log(x[, base])
With one argument, return the natural logarithm of x (to base e).
With two arguments, return the logarithm of x to the given base, calculated as log(x)/log(base).
Where is that documented?
Upvotes: 2
Views: 1294
Reputation: 298
I think this thread is useful since python now uses long ints, the trick to avoid overflow is the use of _PyLong_Frexp
function see here and an alternative formula to compute the log
function even after an OverflowError
is raised when trying to convert a long int to a Double, check loghelper
at this module.
_PyLong_Frexp
returns an approximation to the initial long int arg
, given inside loghelper
with the help of a double x
and an exponent e
(arg~x*2**e
) and the log
is calculated as log~log(x*2**e)=log(x)+log(2)*e
. I am missing the specifics of the approximation using x,e
but you can find it in the implementation of _PyLong_Frexp
in the link provided.
Upvotes: 1
Reputation: 140256
I finally dug into python math lib source code and found this:
/* A decent logarithm is easy to compute even for huge ints, but libm can't
do that by itself -- loghelper can. func is log or log10, and name is
"log" or "log10". Note that overflow of the result isn't possible: an int
can contain no more than INT_MAX * SHIFT bits, so has value certainly less
than 2**(2**64 * 2**16) == 2**2**80, and log2 of that is 2**80, which is
small enough to fit in an IEEE single. log and log10 are even smaller.
However, intermediate overflow is possible for an int if the number of bits
in that int is larger than PY_SSIZE_T_MAX. */
static PyObject*
loghelper(PyObject* arg, double (*func)(double), const char *funcname)
{
/* If it is int, do it ourselves. */
if (PyLong_Check(arg)) {
double x, result;
Py_ssize_t e;
...
I'll spare you the rest of the source (check the link), but what I understand from it is that Python checks if the passed argument is integer, and if it is, don't use math lib (If it is int, do it ourselves.) comment. Also: A decent logarithm is easy to compute even for huge ints, but libm can't do that by itself -- loghelper can
If it's a double, then call native math library.
From the source comments, we see that Python tries the hardest to provide the result even in case of the overflow (Here the conversion to double overflowed, but it's possible to compute the log anyway. Clear the exception and continue)
So thanks to the python wrapping of the log
function, Python is able to compute logarithm of huge integers (which is specific to some functions, since some others like sqrt
cannot do it), and it's documented, but only in the source code, probably making it an implementation detail as Jon hinted.
Upvotes: 4