Commit cec3f138 authored by Mark Dickinson's avatar Mark Dickinson

Yet more explicit special case handling to make

math.pow behave on alpha Tru64.  All IEEE 754
special values are now handled directly; only
the finite**finite case is handled by libm.
parent b2f70902
...@@ -498,6 +498,18 @@ class MathTests(unittest.TestCase): ...@@ -498,6 +498,18 @@ class MathTests(unittest.TestCase):
self.assertEqual(math.pow(-1.1, INF), INF) self.assertEqual(math.pow(-1.1, INF), INF)
self.assertEqual(math.pow(-1.9, INF), INF) self.assertEqual(math.pow(-1.9, INF), INF)
# pow(x, y) should work for x negative, y an integer
self.ftest('(-2.)**3.', math.pow(-2.0, 3.0), -8.0)
self.ftest('(-2.)**2.', math.pow(-2.0, 2.0), 4.0)
self.ftest('(-2.)**1.', math.pow(-2.0, 1.0), -2.0)
self.ftest('(-2.)**0.', math.pow(-2.0, 0.0), 1.0)
self.ftest('(-2.)**-0.', math.pow(-2.0, -0.0), 1.0)
self.ftest('(-2.)**-1.', math.pow(-2.0, -1.0), -0.5)
self.ftest('(-2.)**-2.', math.pow(-2.0, -2.0), 0.25)
self.ftest('(-2.)**-3.', math.pow(-2.0, -3.0), -0.125)
self.assertRaises(ValueError, math.pow, -2.0, -0.5)
self.assertRaises(ValueError, math.pow, -2.0, 0.5)
# the following tests have been commented out since they don't # the following tests have been commented out since they don't
# really belong here: the implementation of ** for floats is # really belong here: the implementation of ** for floats is
# independent of the implemention of math.pow # independent of the implemention of math.pow
......
...@@ -522,7 +522,7 @@ math_pow(PyObject *self, PyObject *args) ...@@ -522,7 +522,7 @@ math_pow(PyObject *self, PyObject *args)
{ {
PyObject *ox, *oy; PyObject *ox, *oy;
double r, x, y; double r, x, y;
int y_is_odd; int odd_y;
if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy)) if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy))
return NULL; return NULL;
...@@ -531,53 +531,61 @@ math_pow(PyObject *self, PyObject *args) ...@@ -531,53 +531,61 @@ math_pow(PyObject *self, PyObject *args)
if ((x == -1.0 || y == -1.0) && PyErr_Occurred()) if ((x == -1.0 || y == -1.0) && PyErr_Occurred())
return NULL; return NULL;
/* deal directly with various special cases, to cope with problems on /* deal directly with IEEE specials, to cope with problems on various
various platforms whose semantics don't exactly match C99 */ platforms whose semantics don't exactly match C99 */
if (!Py_IS_FINITE(x) || !Py_IS_FINITE(y)) {
/* 1**x, x**0, and (-1)**(+-infinity) return 1., even if x is NaN or errno = 0;
an infinity. */ if (Py_IS_NAN(x))
if (x == 1. || y == 0. || (x == -1. && Py_IS_INFINITY(y))) r = y == 0. ? 1. : x; /* NaN**0 = 1 */
return PyFloat_FromDouble(1.); else if (Py_IS_NAN(y))
/* otherwise, return a NaN if either input was a NaN */ r = x == 1. ? 1. : y; /* 1**NaN = 1 */
if (Py_IS_NAN(x)) else if (Py_IS_INFINITY(x)) {
return PyFloat_FromDouble(x); odd_y = Py_IS_FINITE(y) && fmod(fabs(y), 2.0) == 1.0;
if (Py_IS_NAN(y)) if (y > 0.)
return PyFloat_FromDouble(y); r = odd_y ? x : fabs(x);
/* inf ** (nonzero, non-NaN) is one of +-0, +-infinity */ else if (y == 0.)
if (Py_IS_INFINITY(x) && !Py_IS_NAN(y)) { r = 1.;
y_is_odd = Py_IS_FINITE(y) && fmod(fabs(y), 2.0) == 1.0; else /* y < 0. */
if (y > 0.) r = odd_y ? copysign(0., x) : 0.;
r = y_is_odd ? x : fabs(x); }
else else if (Py_IS_INFINITY(y)) {
r = y_is_odd ? copysign(0., x) : 0.; if (fabs(x) == 1.0)
return PyFloat_FromDouble(r); r = 1.;
} else if (y > 0. && fabs(x) > 1.0)
r = y;
errno = 0; else if (y < 0. && fabs(x) < 1.0) {
PyFPE_START_PROTECT("in math_pow", return 0); r = -y; /* result is +inf */
r = pow(x, y); if (x == 0.) /* 0**-inf: divide-by-zero */
PyFPE_END_PROTECT(r); errno = EDOM;
if (Py_IS_NAN(r)) { }
errno = EDOM; else
r = 0.;
}
} }
/* an infinite result arises either from: else {
/* let libm handle finite**finite */
(A) (+/-0.)**negative, errno = 0;
(B) overflow of x**y with both x and y finite (and x nonzero) PyFPE_START_PROTECT("in math_pow", return 0);
(C) (+/-inf)**positive, or r = pow(x, y);
(D) x**inf with |x| > 1, or x**-inf with |x| < 1. PyFPE_END_PROTECT(r);
/* a NaN result should arise only from (-ve)**(finite
In case (A) we want ValueError to be raised. In case (B) non-integer); in this case we want to raise ValueError. */
OverflowError should be raised. In cases (C) and (D) the infinite if (!Py_IS_FINITE(r)) {
result should be returned. if (Py_IS_NAN(r)) {
*/ errno = EDOM;
else if (Py_IS_INFINITY(r)) { }
if (x == 0.) /*
errno = EDOM; an infinite result here arises either from:
else if (Py_IS_FINITE(x) && Py_IS_FINITE(y)) (A) (+/-0.)**negative (-> divide-by-zero)
errno = ERANGE; (B) overflow of x**y with x and y finite
else */
errno = 0; else if (Py_IS_INFINITY(r)) {
if (x == 0.)
errno = EDOM;
else
errno = ERANGE;
}
}
} }
if (errno && is_error(r)) if (errno && is_error(r))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment