Index: Lib/test/test_math.py =================================================================== --- Lib/test/test_math.py (revision 62509) +++ Lib/test/test_math.py (working copy) @@ -374,6 +374,23 @@ self.assertEquals(math.ldexp(NINF, -213), NINF) self.assert_(math.isnan(math.ldexp(NAN, 0))) + # test cases where second argument is larger than a Py_ssize_t + self.assertEquals(math.ldexp(INF, -10**20), INF) + self.assertEquals(math.ldexp(NINF, -10**20), NINF) + self.assertEquals(math.ldexp(1., -10**20), 0.) + self.assertEquals(math.ldexp(-1., -10**20), -0.) + self.assertEquals(math.ldexp(0., -10**20), 0.) + self.assertEquals(math.ldexp(-0., -10**20), -0.) + self.assert_(math.isnan(math.ldexp(NAN, -10**20))) + + self.assertRaises(OverflowError, math.ldexp, 1., 10**20) + self.assertRaises(OverflowError, math.ldexp, -1., 10**20) + self.assertEquals(math.ldexp(0., 10**20), 0.) + self.assertEquals(math.ldexp(-0., 10**20), -0.) + self.assertEquals(math.ldexp(INF, 10**20), INF) + self.assertEquals(math.ldexp(NINF, 10**20), NINF) + self.assert_(math.isnan(math.ldexp(NAN, 10**20))) + def testLog(self): self.assertRaises(TypeError, math.log) self.ftest('log(1/e)', math.log(1/math.e), -1) Index: Modules/mathmodule.c =================================================================== --- Modules/mathmodule.c (revision 62509) +++ Modules/mathmodule.c (working copy) @@ -349,23 +349,64 @@ 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; + + 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; + } + 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)) - errno = ERANGE; - /* Windows MSVC8 sets errno = EDOM on ldexp(NaN, i); - we unset it to avoid raising a ValueError here. */ - if (errno == EDOM) - errno = 0; - if (errno && is_error(r)) - return NULL; - else - return PyFloat_FromDouble(r); + /* NaNs, zeros and infinities are returned unchanged */ + if (x == 0. || !Py_IS_FINITE(x)) { + r = x; + } else if (exp > INT_MAX) { + errno = ERANGE; /* overflow */ + r = copysign(Py_HUGE_VAL, x); + } else if (exp < INT_MIN) { + r = copysign(0., x); + } else { + PyFPE_START_PROTECT("in math_ldexp", return 0); + r = ldexp(x, (int)exp); + PyFPE_END_PROTECT(r); + if (Py_IS_FINITE(x) && Py_IS_INFINITY(r)) + errno = ERANGE; + /* Windows MSVC8 sets errno = EDOM on ldexp(NaN, i); + we unset it to avoid raising a ValueError here. */ + if (errno == EDOM) + errno = 0; + if (errno && is_error(r)) + return NULL; + } + return PyFloat_FromDouble(r); } PyDoc_STRVAR(math_ldexp_doc,