about summary refs log tree commit diff
path: root/sysdeps/ieee754/flt-32
diff options
context:
space:
mode:
authorSzabolcs Nagy <szabolcs.nagy@arm.com>2018-12-10 11:08:36 +0000
committerSzabolcs Nagy <szabolcs.nagy@arm.com>2018-12-11 10:01:43 +0000
commit505b5b292293a5d6bd4046a6bc7f8c2381a33da4 (patch)
treefeeacf415d6fdbb306f2911deede485a6d92fda7 /sysdeps/ieee754/flt-32
parent304c61a24f909168c16793ccf7c686237e53d003 (diff)
downloadglibc-505b5b292293a5d6bd4046a6bc7f8c2381a33da4.tar.gz
glibc-505b5b292293a5d6bd4046a6bc7f8c2381a33da4.tar.xz
glibc-505b5b292293a5d6bd4046a6bc7f8c2381a33da4.zip
Fix powf overflow handling in non-nearest rounding mode [BZ #23961]
The threshold value at which powf overflows depends on the rounding mode
and the current check did not take this into account. So when the result
was rounded away from zero it could become infinity without setting
errno to ERANGE.

Example: pow(0x1.7ac7cp+5, 23) is 0x1.fffffep+127 + 0.1633ulp

If the result goes above 0x1.fffffep+127 + 0.5ulp then errno is set,
which is fine in nearest rounding mode, but

  powf(0x1.7ac7cp+5, 23) is inf in upward rounding mode
  powf(-0x1.7ac7cp+5, 23) is -inf in downward rounding mode

and the previous implementation did not set errno in these cases.

The fix tries to avoid affecting the common code path or calling a
function that may introduce a stack frame, so float arithmetics is used
to check the rounding mode and the threshold is selected accordingly.

	[BZ #23961]
	* math/auto-libm-test-in: Add new test case.
	* math/auto-libm-test-out-pow: Regenerated.
	* sysdeps/ieee754/flt-32/e_powf.c (__powf): Fix overflow check.
Diffstat (limited to 'sysdeps/ieee754/flt-32')
-rw-r--r--sysdeps/ieee754/flt-32/e_powf.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/sysdeps/ieee754/flt-32/e_powf.c b/sysdeps/ieee754/flt-32/e_powf.c
index d0c912188f..965f1fc2e7 100644
--- a/sysdeps/ieee754/flt-32/e_powf.c
+++ b/sysdeps/ieee754/flt-32/e_powf.c
@@ -17,6 +17,8 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <math.h>
+#include <math-barriers.h>
+#include <math-narrow-eval.h>
 #include <stdint.h>
 #include <shlib-compat.h>
 #include <libm-alias-float.h>
@@ -207,7 +209,17 @@ __powf (float x, float y)
     {
       /* |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