]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Fix pow (qNaN, 0) result with -lieee (bug 20919), remove dead parts of wrappers.
authorJoseph Myers <joseph@codesourcery.com>
Fri, 2 Dec 2016 22:50:46 +0000 (22:50 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Fri, 2 Dec 2016 22:50:46 +0000 (22:50 +0000)
The dbl-64 implementation of __ieee754_pow returns a NaN for pow
(qNaN, 0) when it should return 1.  Normally this is covered up by the
wrappers ending up calling __kernel_standard which fixes up the result
for this case, but for -lieee the wrappers are bypassed and the bad
result gets through as a return value.

Now, the wrappers fixing this are dealing with variant error handling
that wants a result of NaN for pow (qNaN, 0), and only ever call
__kernel_standard for this case if NaN resulted from __ieee754_pow.
This leads to a question of whether the dbl-64 code might be
deliberately returning NaN in order to use those code paths.  However,
I can find no sign that this is deliberate.  If it were deliberate one
would expect other implementations to do the same, and would expect
the return of NaN to be very old, but it appears it came in by
accident when the present e_pow.c implementation replaced an fdlibm
implementation in 2001.  So it appears to be unintended that this path
through the pow wrapper could be used at all.

So this patch fixes the implementation to return 1 in this case as
expected.  This is consistent with all the other implementations.  The
relevant path through the wrappers is now unreachable, so is removed
(which is the main motivation of this patch: to avoid that path
becoming accidentally reachable when implementing TS 18661-1 semantics
that pow (sNaN, 0) should return qNaN with "invalid" raised).  Another
path that would require __ieee754_pow (0, 0) to return 0 is also
unreachable (as all implementations return 1, in accordance with C99
semantics), so is removed as well.

Note: we don't have anything set up to test -lieee, which in any case
is obsolescent (at some point we should remove the ability for new
programs to access _LIB_VERSION or define matherr and have it called
by glibc).  So testing will be implicit through sNaN tests added when
making sNaN inputs work correctly for pow functions.

Tested for x86_64 and x86.

[BZ #20919]
* sysdeps/ieee754/dbl-64/e_pow.c (__ieee754_pow): Do not return
NaN first argument when raised to power 0.
* math/w_pow.c (__pow): Do not check for NaN or zero results from
raising to power zero.
* math/w_powf.c (__powf): Likewise.
* math/w_powl.c (__powl): Likewise.
* sysdeps/ieee754/k_standard.c (__kernel_standard): Do not handle
pow (0, 0) or pow (NaN, 0).

ChangeLog
math/w_pow.c
math/w_powf.c
math/w_powl.c
sysdeps/ieee754/dbl-64/e_pow.c
sysdeps/ieee754/k_standard.c

index e4a41d6a3c620cee8192f051e075e4c2ff14a6b7..42a432d6e19c6585a63dd665ab15534726fad5d8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2016-12-02  Joseph Myers  <joseph@codesourcery.com>
+
+       [BZ #20919]
+       * sysdeps/ieee754/dbl-64/e_pow.c (__ieee754_pow): Do not return
+       NaN first argument when raised to power 0.
+       * math/w_pow.c (__pow): Do not check for NaN or zero results from
+       raising to power zero.
+       * math/w_powf.c (__powf): Likewise.
+       * math/w_powl.c (__powl): Likewise.
+       * sysdeps/ieee754/k_standard.c (__kernel_standard): Do not handle
+       pow (0, 0) or pow (NaN, 0).
+
 2016-12-02  Carlos O'Donell  <carlos@redhat.com>
 
        [BZ #20918]
index 12c0591d34189518e2b8f96245a21b15b1f46a28..ed79dbda05c841e123b59c7e763e12f279fdc89a 100644 (file)
@@ -29,13 +29,7 @@ __pow (double x, double y)
     {
       if (_LIB_VERSION != _IEEE_)
        {
-         if (isnan (x))
-           {
-             if (y == 0.0)
-               /* pow(NaN,0.0) */
-               return __kernel_standard (x, y, 42);
-           }
-         else if (isfinite (x) && isfinite (y))
+         if (isfinite (x) && isfinite (y))
            {
              if (isnan (z))
                /* pow neg**non-int */
@@ -55,19 +49,11 @@ __pow (double x, double y)
            }
        }
     }
-  else if (__builtin_expect (z == 0.0, 0) && isfinite (x) && isfinite (y)
+  else if (__builtin_expect (z == 0.0, 0)
+          && isfinite (x) && x != 0 && isfinite (y)
           && _LIB_VERSION != _IEEE_)
-    {
-      if (x == 0.0)
-       {
-         if (y == 0.0)
-           /* pow(0.0,0.0) */
-           return __kernel_standard (x, y, 20);
-       }
-      else
-       /* pow underflow */
-       return __kernel_standard (x, y, 22);
-    }
+    /* pow underflow */
+    return __kernel_standard (x, y, 22);
 
   return z;
 }
index 2e786e2f4e644d37acc71bd68e7575538baa573f..ec157a3a13fc8cb56f57f2478588bda21d4859bd 100644 (file)
@@ -29,13 +29,7 @@ __powf (float x, float y)
     {
       if (_LIB_VERSION != _IEEE_)
        {
-         if (isnan (x))
-           {
-             if (y == 0.0f)
-               /* pow(NaN,0.0) */
-               return __kernel_standard_f (x, y, 142);
-           }
-         else if (isfinite (x) && isfinite (y))
+         if (isfinite (x) && isfinite (y))
            {
              if (isnan (z))
                /* pow neg**non-int */
@@ -55,19 +49,11 @@ __powf (float x, float y)
            }
        }
     }
-  else if (__builtin_expect (z == 0.0f, 0) && isfinite (x) && isfinite (y)
+  else if (__builtin_expect (z == 0.0f, 0)
+          && isfinite (x) && x != 0 && isfinite (y)
           && _LIB_VERSION != _IEEE_)
-    {
-      if (x == 0.0f)
-       {
-         if (y == 0.0f)
-           /* pow(0.0,0.0) */
-           return __kernel_standard_f (x, y, 120);
-       }
-      else
-       /* pow underflow */
-       return __kernel_standard_f (x, y, 122);
-    }
+    /* pow underflow */
+    return __kernel_standard_f (x, y, 122);
 
   return z;
 }
index be02e1eacc5cc7e84c2709526608711f5cc2b7a5..9b86651f55137090974597afab2e3d00ea7ea361 100644 (file)
@@ -29,13 +29,7 @@ __powl (long double x, long double y)
     {
       if (_LIB_VERSION != _IEEE_)
        {
-         if (isnan (x))
-           {
-             if (y == 0.0L)
-               /* pow(NaN,0.0) */
-               return __kernel_standard_l (x, y, 242);
-           }
-         else if (isfinite (x) && isfinite (y))
+         if (isfinite (x) && isfinite (y))
            {
              if (isnan (z))
                /* pow neg**non-int */
@@ -55,19 +49,11 @@ __powl (long double x, long double y)
            }
        }
     }
-  else if (__builtin_expect (z == 0.0L, 0) && isfinite (x) && isfinite (y)
+  else if (__builtin_expect (z == 0.0L, 0)
+          && isfinite (x) && x != 0 && isfinite (y)
           && _LIB_VERSION != _IEEE_)
-    {
-      if (x == 0.0L)
-       {
-         if (y == 0.0L)
-           /* pow(0.0,0.0) */
-           return __kernel_standard_l (x, y, 220);
-       }
-      else
-       /* pow underflow */
-       return __kernel_standard_l (x, y, 222);
-    }
+    /* pow underflow */
+    return __kernel_standard_l (x, y, 222);
 
   return z;
 }
index bd758b5979aeabc57f0f774d8c8cab948ba10f2f..db6ecf76e5ac0cdd8e0b52da5bc0dfb7cc103e11 100644 (file)
@@ -73,7 +73,8 @@ __ieee754_pow (double x, double y)
     {                          /* of y */
       qx = u.i[HIGH_HALF] & 0x7fffffff;
       /* Is x a NaN?  */
-      if (((qx == 0x7ff00000) && (u.i[LOW_HALF] != 0)) || (qx > 0x7ff00000))
+      if ((((qx == 0x7ff00000) && (u.i[LOW_HALF] != 0)) || (qx > 0x7ff00000))
+         && y != 0)
        return x;
       if (y == 1.0)
        return x;
index c8aebbff903d0013eaf5d2f695a17a071dbb8892..b100b3e3519e174e215e4a876319c7c5d7ecac9f 100644 (file)
@@ -60,7 +60,6 @@ static double zero = 0.0;     /* used as const */
  *     17-- log(x<0)
  *     18-- log10(0)
  *     19-- log10(x<0)
- *     20-- pow(0.0,0.0)
  *     21-- pow(x,y) overflow
  *     22-- pow(x,y) underflow
  *     23-- pow(0,negative)
@@ -82,7 +81,6 @@ static double zero = 0.0;     /* used as const */
  *     39-- yn(x>X_TLOSS, n)
  *     40-- tgamma(finite) overflow
  *     41-- tgamma(-integer)
- *     42-- pow(NaN,0.0)
  *     43-- +0**neg
  *     44-- exp2 overflow
  *     45-- exp2 underflow
@@ -461,20 +459,6 @@ __kernel_standard(double x, double y, int type)
                  __set_errno (EDOM);
                }
                break;
-           case 20:
-           case 120:
-           case 220:
-               /* pow(0.0,0.0) */
-               /* error only if _LIB_VERSION == _SVID_ */
-               exc.type = DOMAIN;
-               exc.name = CSTR ("pow");
-               exc.retval = zero;
-               if (_LIB_VERSION != _SVID_) exc.retval = 1.0;
-               else if (!matherr(&exc)) {
-                       (void) WRITE2("pow(0,0): DOMAIN error\n", 23);
-                       __set_errno (EDOM);
-               }
-               break;
            case 21:
            case 121:
            case 221:
@@ -845,20 +829,6 @@ __kernel_standard(double x, double y, int type)
                  __set_errno (EDOM);
                }
                break;
-           case 42:
-           case 142:
-           case 242:
-               /* pow(NaN,0.0) */
-               /* error only if _LIB_VERSION == _SVID_ & _XOPEN_ */
-               exc.type = DOMAIN;
-               exc.name = CSTR ("pow");
-               exc.retval = x;
-               if (_LIB_VERSION == _IEEE_ ||
-                   _LIB_VERSION == _POSIX_) exc.retval = 1.0;
-               else if (!matherr(&exc)) {
-                       __set_errno (EDOM);
-               }
-               break;
 
            case 44:
            case 144: