From c97c9096ed05c89041b2aab9578489ca634c9375 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Mon, 9 Feb 2009 14:18:43 +0000 Subject: Issue #4575: fix Py_IS_INFINITY macro to work correctly on x87 FPUs. It now forces its argument to double before testing for infinity. --- Include/pymath.h | 29 ++++++++++++++++++++++++----- Misc/NEWS | 3 +++ Python/pymath.c | 13 +++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Include/pymath.h b/Include/pymath.h index 0631b93..6ad174d 100644 --- a/Include/pymath.h +++ b/Include/pymath.h @@ -77,6 +77,21 @@ extern double copysign(double, double); #define Py_MATH_E 2.7182818284590452354 #endif +/* On x86, Py_FORCE_DOUBLE forces a floating-point number out of an x87 FPU + register and into a 64-bit memory location, rounding from extended + precision to double precision in the process. On other platforms it does + nothing. */ + +/* we take double rounding as evidence of x87 usage */ +#ifndef Py_FORCE_DOUBLE +# ifdef X87_DOUBLE_ROUNDING +PyAPI_FUNC(double) _Py_force_double(double); +# define Py_FORCE_DOUBLE(X) (_Py_force_double(X)) +# else +# define Py_FORCE_DOUBLE(X) (X) +# endif +#endif + /* Py_IS_NAN(X) * Return 1 if float or double arg is a NaN, else 0. * Caution: @@ -101,14 +116,18 @@ extern double copysign(double, double); * This implementation may set the underflow flag if |X| is very small; * it really can't be implemented correctly (& easily) before C99. * Override in pyconfig.h if you have a better spelling on your platform. + * Py_FORCE_DOUBLE is used to avoid getting false negatives from a + * non-infinite value v sitting in an 80-bit x87 register such that + * v becomes infinite when spilled from the register to 64-bit memory. * Note: PC/pyconfig.h defines Py_IS_INFINITY as _isinf */ #ifndef Py_IS_INFINITY -#if defined HAVE_DECL_ISINF && HAVE_DECL_ISINF == 1 -#define Py_IS_INFINITY(X) isinf(X) -#else -#define Py_IS_INFINITY(X) ((X) && (X)*0.5 == (X)) -#endif +# if defined HAVE_DECL_ISINF && HAVE_DECL_ISINF == 1 +# define Py_IS_INFINITY(X) isinf(X) +# else +# define Py_IS_INFINITY(X) ((X) && \ + (Py_FORCE_DOUBLE(X)*0.5 == Py_FORCE_DOUBLE(X))) +# endif #endif /* Py_IS_FINITE(X) diff --git a/Misc/NEWS b/Misc/NEWS index c926347..9f56bb8 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 2.7 alpha 1 Core and Builtins ----------------- +- Issue #4575: Fix Py_IS_INFINITY macro to work correctly on x87 FPUs: + it now forces its argument to double before testing for infinity. + - Issue #4978: Passing keyword arguments as unicode strings is now allowed. - Issue 1242657: the __len__() and __length_hint__() calls in several tools diff --git a/Python/pymath.c b/Python/pymath.c index 5cf61ab..5d09b4c 100644 --- a/Python/pymath.c +++ b/Python/pymath.c @@ -1,5 +1,18 @@ #include "Python.h" +#ifdef X87_DOUBLE_ROUNDING +/* On x86 platforms using an x87 FPU, this function is called from the + Py_FORCE_DOUBLE macro (defined in pymath.h) to force a floating-point + number out of an 80-bit x87 FPU register and into a 64-bit memory location, + thus rounding from extended precision to double precision. */ +double _Py_force_double(double x) +{ + volatile double y; + y = x; + return y; +} +#endif + #ifndef HAVE_HYPOT double hypot(double x, double y) { -- cgit v0.12