diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2008-05-09 17:54:23 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2008-05-09 17:54:23 (GMT) |
commit | f8476c15730939c4ee64d94f08c2d6e40b09195d (patch) | |
tree | 4b2107074cba7baf8bec2ceff3a049dcf2698f9b /Modules | |
parent | 8bd5334a9e192bcd1c182574d585179bc9d8be2d (diff) | |
download | cpython-f8476c15730939c4ee64d94f08c2d6e40b09195d.zip cpython-f8476c15730939c4ee64d94f08c2d6e40b09195d.tar.gz cpython-f8476c15730939c4ee64d94f08c2d6e40b09195d.tar.bz2 |
Issue #2487. math.ldexp(x, n) raised OverflowError when n was large and
negative; fix to return an (appropriately signed) zero instead.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/mathmodule.c | 66 |
1 files changed, 54 insertions, 12 deletions
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 201ffc4..c4ac69a 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -349,23 +349,65 @@ static PyObject * math_ldexp(PyObject *self, PyObject *args) { double x, r; - int exp; - if (! PyArg_ParseTuple(args, "di:ldexp", &x, &exp)) + PyObject *oexp; + long exp; + if (! PyArg_ParseTuple(args, "dO:ldexp", &x, &oexp)) return NULL; - errno = 0; - PyFPE_START_PROTECT("in math_ldexp", return 0) - r = ldexp(x, exp); - PyFPE_END_PROTECT(r) - if (Py_IS_FINITE(x) && Py_IS_INFINITY(r)) + + if (PyLong_Check(oexp)) { + /* on overflow, replace exponent with either LONG_MAX + or LONG_MIN, depending on the sign. */ + exp = PyLong_AsLong(oexp); + if (exp == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + if (Py_SIZE(oexp) < 0) { + exp = LONG_MIN; + } + else { + exp = LONG_MAX; + } + PyErr_Clear(); + } + else { + /* propagate any unexpected exception */ + return NULL; + } + } + } + else if (PyInt_Check(oexp)) { + exp = PyInt_AS_LONG(oexp); + } + else { + PyErr_SetString(PyExc_TypeError, + "Expected an int or long as second argument " + "to ldexp."); + return NULL; + } + + if (x == 0. || !Py_IS_FINITE(x)) { + /* NaNs, zeros and infinities are returned unchanged */ + r = x; + errno = 0; + } else if (exp > INT_MAX) { + /* overflow */ + r = copysign(Py_HUGE_VAL, x); errno = ERANGE; - /* Windows MSVC8 sets errno = EDOM on ldexp(NaN, i); - we unset it to avoid raising a ValueError here. */ - if (errno == EDOM) + } else if (exp < INT_MIN) { + /* underflow to +-0 */ + r = copysign(0., x); errno = 0; + } else { + errno = 0; + PyFPE_START_PROTECT("in math_ldexp", return 0); + r = ldexp(x, (int)exp); + PyFPE_END_PROTECT(r); + if (Py_IS_INFINITY(r)) + errno = ERANGE; + } + if (errno && is_error(r)) return NULL; - else - return PyFloat_FromDouble(r); + return PyFloat_FromDouble(r); } PyDoc_STRVAR(math_ldexp_doc, |