Raise OverflowError when appropriate on long->float conversion. Most of

the fiddling is simply due to that no caller of PyLong_AsDouble ever
checked for failure (so that's fixing old bugs).  PyLong_AsDouble is much
faster for big inputs now too, but that's more of a happy consequence
than a design goal.
This commit is contained in:
Tim Peters 2001-09-04 05:14:19 +00:00
parent 1832de4bc0
commit 9fffa3eea3
5 changed files with 76 additions and 23 deletions

View File

@ -328,6 +328,42 @@ def test_auto_overflow():
raise TestFailed("pow%r should have raised "
"TypeError" % ((longx, longy, long(z))))
# ---------------------------------------- tests of long->float overflow
def test_float_overflow():
import math
if verbose:
print "long->float overflow"
for x in -2.0, -1.0, 0.0, 1.0, 2.0:
verify(float(long(x)) == x)
huge = 1L << 30000
mhuge = -huge
namespace = {'huge': huge, 'mhuge': mhuge, 'math': math}
for test in ["float(huge)", "float(mhuge)",
"complex(huge)", "complex(mhuge)",
"complex(huge, 1)", "complex(mhuge, 1)",
"complex(1, huge)", "complex(1, mhuge)",
"1. + huge", "huge + 1.", "1. + mhuge", "mhuge + 1.",
"1. - huge", "huge - 1.", "1. - mhuge", "mhuge - 1.",
"1. * huge", "huge * 1.", "1. * mhuge", "mhuge * 1.",
"1. // huge", "huge // 1.", "1. // mhuge", "mhuge // 1.",
"1. / huge", "huge / 1.", "1. / mhuge", "mhuge / 1.",
"1. ** huge", "huge ** 1.", "1. ** mhuge", "mhuge ** 1.",
"math.sin(huge)", "math.sin(mhuge)",
"math.log(huge)", "math.log(mhuge)", # should do better
"math.sqrt(huge)", "math.sqrt(mhuge)", # should do better
"math.log10(huge)", "math.log10(mhuge)", # should do better
"math.floor(huge)", "math.floor(mhuge)"]:
try:
eval(test, namespace)
except OverflowError:
pass
else:
raise TestFailed("expected OverflowError from %s" % test)
# ---------------------------------------------------------------- do it
test_division()
@ -335,3 +371,4 @@ test_bitop_identities()
test_format()
test_misc()
test_auto_overflow()
test_float_overflow()

View File

@ -3,6 +3,9 @@ What's New in Python 2.2a3?
Core
- Conversion of long to float now raises OverflowError if the long is too
big to represent as a C double.
- The 3-argument builtin pow() no longer allows a third non-None argument
if either of the first two arguments is a float, or if both are of
integer types and the second argument is negative (in which latter case
@ -95,6 +98,15 @@ Build
API
- Note that PyLong_AsDouble can fail! This has always been true, but no
callers checked for it. It's more likely to fail now, because overflow
errors are properly detected now. The proper way to check:
double x = PyLong_AsDouble(some_long_object);
if (x == -1.0 && PyErr_Occurred()) {
/* The conversion failed. */
}
- The GC API has been changed. Extensions that use the old API will still
compile but will not participate in GC. To upgrade an extension
module:

View File

@ -522,6 +522,8 @@ complex_coerce(PyObject **pv, PyObject **pw)
}
else if (PyLong_Check(*pw)) {
cval.real = PyLong_AsDouble(*pw);
if (cval.real == -1.0 && PyErr_Occurred())
return -1;
*pw = PyComplex_FromCComplex(cval);
Py_INCREF(*pv);
return 0;

View File

@ -271,8 +271,7 @@ PyFloat_AsStringEx(char *buf, PyFloatObject *v, int precision)
return obj;
static int
convert_to_double(PyObject **v,
double *dbl)
convert_to_double(PyObject **v, double *dbl)
{
register PyObject *obj = *v;
@ -280,9 +279,11 @@ convert_to_double(PyObject **v,
*dbl = (double)PyInt_AS_LONG(obj);
}
else if (PyLong_Check(obj)) {
PyFPE_START_PROTECT("convert_to_double", {*v=NULL;return -1;})
*dbl = PyLong_AsDouble(obj);
PyFPE_END_PROTECT(*dbl)
if (*dbl == -1.0 && PyErr_Occurred()) {
*v = NULL;
return -1;
}
}
else {
Py_INCREF(Py_NotImplemented);

View File

@ -531,27 +531,28 @@ _PyLong_AsScaledDouble(PyObject *vv, int *exponent)
double
PyLong_AsDouble(PyObject *vv)
{
register PyLongObject *v;
int e;
double x;
double multiplier = (double) (1L << SHIFT);
int i, sign;
if (vv == NULL || !PyLong_Check(vv)) {
PyErr_BadInternalCall();
return -1;
}
v = (PyLongObject *)vv;
i = v->ob_size;
sign = 1;
x = 0.0;
if (i < 0) {
sign = -1;
i = -(i);
}
while (--i >= 0) {
x = x*multiplier + (double)v->ob_digit[i];
}
return x * sign;
x = _PyLong_AsScaledDouble(vv, &e);
if (x == -1.0 && PyErr_Occurred())
return -1.0;
if (e > INT_MAX / SHIFT)
goto overflow;
errno = 0;
x = ldexp(x, e * SHIFT);
if (errno == ERANGE)
goto overflow;
return x;
overflow:
PyErr_SetString(PyExc_OverflowError,
"long int too large to convert to float");
return -1.0;
}
/* Create a new long (or int) object from a C pointer */
@ -2098,9 +2099,9 @@ static PyObject *
long_float(PyObject *v)
{
double result;
PyFPE_START_PROTECT("long_float", return 0)
result = PyLong_AsDouble(v);
PyFPE_END_PROTECT(result)
if (result == -1.0 && PyErr_Occurred())
return NULL;
return PyFloat_FromDouble(result);
}