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.
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index 0e91f8f..72ee0db 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -522,7 +522,7 @@
{
PyObject *ox, *oy;
double r, x, y;
- int y_is_odd;
+ int odd_y;
if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy))
return NULL;
@@ -531,53 +531,61 @@
if ((x == -1.0 || y == -1.0) && PyErr_Occurred())
return NULL;
- /* deal directly with various special cases, to cope with problems on
- various platforms whose semantics don't exactly match C99 */
-
- /* 1**x, x**0, and (-1)**(+-infinity) return 1., even if x is NaN or
- an infinity. */
- if (x == 1. || y == 0. || (x == -1. && Py_IS_INFINITY(y)))
- return PyFloat_FromDouble(1.);
- /* otherwise, return a NaN if either input was a NaN */
- if (Py_IS_NAN(x))
- return PyFloat_FromDouble(x);
- if (Py_IS_NAN(y))
- return PyFloat_FromDouble(y);
- /* inf ** (nonzero, non-NaN) is one of +-0, +-infinity */
- if (Py_IS_INFINITY(x) && !Py_IS_NAN(y)) {
- y_is_odd = Py_IS_FINITE(y) && fmod(fabs(y), 2.0) == 1.0;
- if (y > 0.)
- r = y_is_odd ? x : fabs(x);
- else
- r = y_is_odd ? copysign(0., x) : 0.;
- return PyFloat_FromDouble(r);
+ /* deal directly with IEEE specials, to cope with problems on various
+ platforms whose semantics don't exactly match C99 */
+ if (!Py_IS_FINITE(x) || !Py_IS_FINITE(y)) {
+ errno = 0;
+ if (Py_IS_NAN(x))
+ r = y == 0. ? 1. : x; /* NaN**0 = 1 */
+ else if (Py_IS_NAN(y))
+ r = x == 1. ? 1. : y; /* 1**NaN = 1 */
+ else if (Py_IS_INFINITY(x)) {
+ odd_y = Py_IS_FINITE(y) && fmod(fabs(y), 2.0) == 1.0;
+ if (y > 0.)
+ r = odd_y ? x : fabs(x);
+ else if (y == 0.)
+ r = 1.;
+ else /* y < 0. */
+ r = odd_y ? copysign(0., x) : 0.;
+ }
+ else if (Py_IS_INFINITY(y)) {
+ if (fabs(x) == 1.0)
+ r = 1.;
+ else if (y > 0. && fabs(x) > 1.0)
+ r = y;
+ else if (y < 0. && fabs(x) < 1.0) {
+ r = -y; /* result is +inf */
+ if (x == 0.) /* 0**-inf: divide-by-zero */
+ errno = EDOM;
+ }
+ else
+ r = 0.;
+ }
}
-
- errno = 0;
- PyFPE_START_PROTECT("in math_pow", return 0);
- r = pow(x, y);
- PyFPE_END_PROTECT(r);
- if (Py_IS_NAN(r)) {
- errno = EDOM;
- }
- /* an infinite result arises either from:
-
- (A) (+/-0.)**negative,
- (B) overflow of x**y with both x and y finite (and x nonzero)
- (C) (+/-inf)**positive, or
- (D) x**inf with |x| > 1, or x**-inf with |x| < 1.
-
- In case (A) we want ValueError to be raised. In case (B)
- OverflowError should be raised. In cases (C) and (D) the infinite
- result should be returned.
- */
- else if (Py_IS_INFINITY(r)) {
- if (x == 0.)
- errno = EDOM;
- else if (Py_IS_FINITE(x) && Py_IS_FINITE(y))
- errno = ERANGE;
- else
- errno = 0;
+ else {
+ /* let libm handle finite**finite */
+ errno = 0;
+ PyFPE_START_PROTECT("in math_pow", return 0);
+ r = pow(x, y);
+ PyFPE_END_PROTECT(r);
+ /* a NaN result should arise only from (-ve)**(finite
+ non-integer); in this case we want to raise ValueError. */
+ if (!Py_IS_FINITE(r)) {
+ if (Py_IS_NAN(r)) {
+ errno = EDOM;
+ }
+ /*
+ an infinite result here arises either from:
+ (A) (+/-0.)**negative (-> divide-by-zero)
+ (B) overflow of x**y with x and y finite
+ */
+ else if (Py_IS_INFINITY(r)) {
+ if (x == 0.)
+ errno = EDOM;
+ else
+ errno = ERANGE;
+ }
+ }
}
if (errno && is_error(r))