Skip to content

Commit 6ecd9e5

Browse files
committed
Merged revisions 77234 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r77234 | mark.dickinson | 2010-01-02 14:45:40 +0000 (Sat, 02 Jan 2010) | 7 lines Refactor some longobject internals: PyLong_AsDouble and _PyLong_AsScaledDouble (the latter renamed to _PyLong_Frexp) now use the same core code. The exponent produced by _PyLong_Frexp now has type Py_ssize_t instead of the previously used int, and no longer needs scaling by PyLong_SHIFT. This frees the math module from having to know anything about the PyLong implementation. This closes issue #5576. ........
1 parent 01f748a commit 6ecd9e5

3 files changed

Lines changed: 168 additions & 240 deletions

File tree

Include/longobject.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ PyAPI_FUNC(PyObject *) PyLong_GetInfo(void);
4444
/* For use by intobject.c only */
4545
PyAPI_DATA(unsigned char) _PyLong_DigitValue[256];
4646

47-
/* _PyLong_AsScaledDouble returns a double x and an exponent e such that
48-
the true value is approximately equal to x * 2**(SHIFT*e). e is >= 0.
49-
x is 0.0 if and only if the input is 0 (in which case, e and x are both
50-
zeroes). Overflow is impossible. Note that the exponent returned must
51-
be multiplied by SHIFT! There may not be enough room in an int to store
52-
e*SHIFT directly. */
53-
PyAPI_FUNC(double) _PyLong_AsScaledDouble(PyObject *vv, int *e);
47+
/* _PyLong_Frexp returns a double x and an exponent e such that the
48+
true value is approximately equal to x * 2**e. e is >= 0. x is
49+
0.0 if and only if the input is 0 (in which case, e and x are both
50+
zeroes); otherwise, 0.5 <= abs(x) < 1.0. On overflow, which is
51+
possible if the number of bits doesn't fit into a Py_ssize_t, sets
52+
OverflowError and returns -1.0 for x, 0 for e. */
53+
PyAPI_FUNC(double) _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e);
5454

5555
PyAPI_FUNC(double) PyLong_AsDouble(PyObject *);
5656
PyAPI_FUNC(PyObject *) PyLong_FromVoidPtr(void *);

Modules/mathmodule.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ raised for division by zero and mod by zero.
5454

5555
#include "Python.h"
5656
#include "_math.h"
57-
#include "longintrepr.h" /* just for SHIFT */
5857

5958
#ifdef _OSF_SOURCE
6059
/* OSF1 5.1 doesn't make this available with XOPEN_SOURCE_EXTENDED defined */
@@ -1342,30 +1341,34 @@ PyDoc_STRVAR(math_modf_doc,
13421341

13431342
/* A decent logarithm is easy to compute even for huge longs, but libm can't
13441343
do that by itself -- loghelper can. func is log or log10, and name is
1345-
"log" or "log10". Note that overflow isn't possible: a long can contain
1346-
no more than INT_MAX * SHIFT bits, so has value certainly less than
1347-
2**(2**64 * 2**16) == 2**2**80, and log2 of that is 2**80, which is
1344+
"log" or "log10". Note that overflow of the result isn't possible: a long
1345+
can contain no more than INT_MAX * SHIFT bits, so has value certainly less
1346+
than 2**(2**64 * 2**16) == 2**2**80, and log2 of that is 2**80, which is
13481347
small enough to fit in an IEEE single. log and log10 are even smaller.
1349-
*/
1348+
However, intermediate overflow is possible for a long if the number of bits
1349+
in that long is larger than PY_SSIZE_T_MAX. */
13501350

13511351
static PyObject*
13521352
loghelper(PyObject* arg, double (*func)(double), char *funcname)
13531353
{
13541354
/* If it is long, do it ourselves. */
13551355
if (PyLong_Check(arg)) {
13561356
double x;
1357-
int e;
1358-
x = _PyLong_AsScaledDouble(arg, &e);
1357+
Py_ssize_t e;
1358+
x = _PyLong_Frexp((PyLongObject *)arg, &e);
1359+
if (x == -1.0 && PyErr_Occurred())
1360+
return NULL;
13591361
if (x <= 0.0) {
13601362
PyErr_SetString(PyExc_ValueError,
13611363
"math domain error");
13621364
return NULL;
13631365
}
1364-
/* Value is ~= x * 2**(e*PyLong_SHIFT), so the log ~=
1365-
log(x) + log(2) * e * PyLong_SHIFT.
1366-
CAUTION: e*PyLong_SHIFT may overflow using int arithmetic,
1367-
so force use of double. */
1368-
x = func(x) + (e * (double)PyLong_SHIFT) * func(2.0);
1366+
/* Special case for log(1), to make sure we get an
1367+
exact result there. */
1368+
if (e == 1 && x == 0.5)
1369+
return PyFloat_FromDouble(0.0);
1370+
/* Value is ~= x * 2**e, so the log ~= log(x) + log(2) * e. */
1371+
x = func(x) + func(2.0) * e;
13691372
return PyFloat_FromDouble(x);
13701373
}
13711374

0 commit comments

Comments
 (0)