Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7852616

Browse files
committed
Return reasonable results for math.log(long) and math.log10(long) (we were
getting Infs, NaNs, or nonsense in 2.1 and before; in yesterday's CVS we were getting OverflowError; but these functions always make good sense for positive arguments, no matter how large).
1 parent 63c9453 commit 7852616

3 files changed

Lines changed: 104 additions & 7 deletions

File tree

Lib/test/test_long.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from test_support import verify, verbose, TestFailed
1+
from test_support import verify, verbose, TestFailed, fcmp
22
from string import join
33
from random import random, randint
44

@@ -353,9 +353,7 @@ def test_float_overflow():
353353
"1. / huge", "huge / 1.", "1. / mhuge", "mhuge / 1.",
354354
"1. ** huge", "huge ** 1.", "1. ** mhuge", "mhuge ** 1.",
355355
"math.sin(huge)", "math.sin(mhuge)",
356-
"math.log(huge)", "math.log(mhuge)", # should do better
357356
"math.sqrt(huge)", "math.sqrt(mhuge)", # should do better
358-
"math.log10(huge)", "math.log10(mhuge)", # should do better
359357
"math.floor(huge)", "math.floor(mhuge)"]:
360358

361359
try:
@@ -364,6 +362,41 @@ def test_float_overflow():
364362
pass
365363
else:
366364
raise TestFailed("expected OverflowError from %s" % test)
365+
366+
# ---------------------------------------------- test huge log and log10
367+
368+
def test_logs():
369+
import math
370+
371+
if verbose:
372+
print "log and log10"
373+
374+
LOG10E = math.log10(math.e)
375+
376+
for exp in range(10) + [100, 1000, 10000]:
377+
value = 10 ** exp
378+
log10 = math.log10(value)
379+
verify(fcmp(log10, exp) == 0)
380+
381+
# log10(value) == exp, so log(value) == log10(value)/log10(e) ==
382+
# exp/LOG10E
383+
expected = exp / LOG10E
384+
log = math.log(value)
385+
verify(fcmp(log, expected) == 0)
386+
387+
for bad in -(1L << 10000), -2L, 0L:
388+
try:
389+
math.log(bad)
390+
raise TestFailed("expected ValueError from log(<= 0)")
391+
except ValueError:
392+
pass
393+
394+
try:
395+
math.log10(bad)
396+
raise TestFailed("expected ValueError from log10(<= 0)")
397+
except ValueError:
398+
pass
399+
367400
# ---------------------------------------------------------------- do it
368401

369402
test_division()
@@ -372,3 +405,4 @@ def test_float_overflow():
372405
test_misc()
373406
test_auto_overflow()
374407
test_float_overflow()
408+
test_logs()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ Core
8181

8282
Library
8383

84+
- math.log and math.log10 now return sensible results for even huge
85+
long arguments. For example, math.log10(10 ** 10000) ~= 10000.0.
86+
8487
- A new function, imp.lock_held(), returns 1 when the import lock is
8588
currently held. See the docs for the imp module.
8689

Modules/mathmodule.c

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* Math module -- standard C math library functions, pi and e */
22

33
#include "Python.h"
4+
#include "longintrepr.h"
45

56
#ifndef _MSC_VER
67
#ifndef __STDC__
@@ -136,10 +137,6 @@ FUNC2(fmod, fmod,
136137
" x % y may differ.")
137138
FUNC2(hypot, hypot,
138139
"hypot(x,y)\n\nReturn the Euclidean distance, sqrt(x*x + y*y).")
139-
FUNC1(log, log,
140-
"log(x)\n\nReturn the natural logarithm of x.")
141-
FUNC1(log10, log10,
142-
"log10(x)\n\nReturn the base-10 logarithm of x.")
143140
#ifdef MPW_3_1 /* This hack is needed for MPW 3.1 but not for 3.2 ... */
144141
FUNC2(pow, power,
145142
"pow(x,y)\n\nReturn x**y (x to the power of y).")
@@ -231,6 +228,69 @@ static char math_modf_doc [] =
231228
"Return the fractional and integer parts of x. Both results carry the sign\n"
232229
"of x. The integer part is returned as a real.";
233230

231+
/* A decent logarithm is easy to compute even for huge longs, but libm can't
232+
do that by itself -- loghelper can. func is log or log10, and name is
233+
"log" or "log10". Note that overflow isn't possible: a long can contain
234+
no more than INT_MAX * SHIFT bits, so has value certainly less than
235+
2**(2**64 * 2**16) == 2**2**80, and log2 of that is 2**80, which is
236+
small enough to fit in an IEEE single. log and log10 are even smaller.
237+
*/
238+
239+
static PyObject*
240+
loghelper(PyObject* args, double (*func)(double), char *name)
241+
{
242+
PyObject *arg;
243+
char format[16];
244+
245+
/* See whether this is a long. */
246+
format[0] = 'O';
247+
format[1] = ':';
248+
strcpy(format + 2, name);
249+
if (! PyArg_ParseTuple(args, format, &arg))
250+
return NULL;
251+
252+
/* If it is long, do it ourselves. */
253+
if (PyLong_Check(arg)) {
254+
double x;
255+
int e;
256+
x = _PyLong_AsScaledDouble(arg, &e);
257+
if (x <= 0.0) {
258+
PyErr_SetString(PyExc_ValueError,
259+
"math domain error");
260+
return NULL;
261+
}
262+
/* Value is ~= x * 2**(e*SHIFT), so the log ~=
263+
log(x) + log(2) * e * SHIFT.
264+
CAUTION: e*SHIFT may overflow using int arithmetic,
265+
so force use of double. */
266+
x = func(x) + func(2.0) * (double)e * (double)SHIFT;
267+
return PyFloat_FromDouble(x);
268+
}
269+
270+
/* Else let libm handle it by itself. */
271+
format[0] = 'd';
272+
return math_1(args, func, format);
273+
}
274+
275+
static PyObject *
276+
math_log(PyObject *self, PyObject *args)
277+
{
278+
return loghelper(args, log, "log");
279+
}
280+
281+
static char math_log_doc[] =
282+
"log(x) -> the natural logarithm (base e) of x.";
283+
284+
static PyObject *
285+
math_log10(PyObject *self, PyObject *args)
286+
{
287+
return loghelper(args, log10, "log10");
288+
}
289+
290+
static char math_log10_doc[] =
291+
"log10(x) -> the base 10 logarithm of x.";
292+
293+
234294
static PyMethodDef math_methods[] = {
235295
{"acos", math_acos, METH_VARARGS, math_acos_doc},
236296
{"asin", math_asin, METH_VARARGS, math_asin_doc},

0 commit comments

Comments
 (0)