]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
math: Fix powf special case [BZ #33563]
authorWilco Dijkstra <wilco.dijkstra@arm.com>
Fri, 24 Oct 2025 14:26:50 +0000 (14:26 +0000)
committerWilco Dijkstra <wilco.dijkstra@arm.com>
Fri, 31 Oct 2025 19:12:47 +0000 (19:12 +0000)
Fix powf (0x1.fffffep+127, 1.0f) to return 0x1.fffffep+127 when
rouding upwards.  Cleanup the special case code - performance
improves by ~1.2%.  This fixes BZ #33563.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
sysdeps/ieee754/flt-32/e_powf.c

index 06587140fbbf47291fae86566efc7946f49ad466..07b68c2bac3f0da025de8eae658f8bf6176dba15 100644 (file)
@@ -202,30 +202,40 @@ __powf (float x, float y)
          ix -= 23 << 23;
        }
     }
-  double_t logx = log2_inline (ix);
-  double_t ylogx = (double) y * logx; /* Note: cannot overflow, y is single prec.  */
+  /* y * log2(x) cannot overflow since y is single precision.  */
+  double_t ylogx = (double) y * log2_inline (ix);
+
+  /* Check whether |y*log(x)| >= 126.  */
   if (__glibc_unlikely ((asuint64 (ylogx) >> 47 & 0xffff)
                        >= asuint64 (126.0 * POWF_SCALE) >> 47))
     {
-      /* |y*log(x)| >= 126.  */
-      if (ylogx > 0x1.fffffffd1d571p+6 * POWF_SCALE)
-       /* |x^y| > 0x1.ffffffp127.  */
-       return __math_oflowf (sign_bias);
-      if (WANT_ROUNDING && WANT_ERRNO
-         && ylogx > 0x1.fffffffa3aae2p+6 * POWF_SCALE)
-       /* |x^y| > 0x1.fffffep127, check if we round away from 0.  */
-       if ((!sign_bias
-            && math_narrow_eval (1.0f + math_opt_barrier (0x1p-25f)) != 1.0f)
-           || (sign_bias
-               && math_narrow_eval (-1.0f - math_opt_barrier (0x1p-25f))
-                    != -1.0f))
-         return __math_oflowf (sign_bias);
+
       if (ylogx <= -150.0 * POWF_SCALE)
        return __math_uflowf (sign_bias);
-#if WANT_ERRNO_UFLOW
-      if (ylogx < -149.0 * POWF_SCALE)
+
+      if (WANT_ERRNO_UFLOW && ylogx < -149.0 * POWF_SCALE)
        return __math_may_uflowf (sign_bias);
-#endif
+
+      /* |x^y| > 0x1.ffffffp127.  */
+      if (!WANT_ROUNDING && ylogx > 0x1.fffffffd1d571p+6 * POWF_SCALE)
+       return __math_oflowf (sign_bias);
+
+      if (WANT_ROUNDING && ylogx > 0x1.fffffffa3aae2p+6 * POWF_SCALE)
+       {
+         if (ylogx > 0x1.fffffffd1d571p+6 * POWF_SCALE)
+           return __math_oflowf (sign_bias);
+
+         /* |x^y| > 0x1.fffffep127, check if we round away from 0.  */
+         if (ylogx != 0x1.fffffffa3aae3p+6 * POWF_SCALE)
+           {
+             float x = math_opt_barrier (0x1p-25f);
+             if ((!sign_bias && math_narrow_eval (1.0f + x) != 1.0f)
+                 || (sign_bias && math_narrow_eval (-1.0f - x) != -1.0f))
+               return __math_oflowf (sign_bias);
+           }
+
+         return sign_bias ? -0x1.fffffep127 : 0x1.fffffep127;
+       }
     }
   return (float) exp2_inline (ylogx, sign_bias);
 }