[PATCH 3/4] math: signal underflow for fmaf results that are tiny before rounding

Matt Turner <[email protected]> Mon, 3 Aug 2026 19:55:08 -0400
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <[email protected]>
fmaf computes the exact result as a double and lets the return convert
it to float, so that conversion is the operation's single rounding and
is what has to signal underflow.  Where the exact result is tiny but
rounds up to the smallest normal float, architectures determining
tininess after rounding do not signal it, because the value they examine
is no longer tiny.

Route the returns through a helper that applies CHECK_NARROW_TINY, which
already decides this by rounding with an unbounded exponent range.  The
raise is redundant on architectures that signal such results themselves.
---
 sysdeps/ieee754/dbl-64/s_fmaf.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git ./sysdeps/ieee754/dbl-64/s_fmaf.c ./sysdeps/ieee754/dbl-64/s_fmaf.c
index 639c273486..dc78e9453a 100644
--- ./sysdeps/ieee754/dbl-64/s_fmaf.c
+++ ./sysdeps/ieee754/dbl-64/s_fmaf.c
@@ -20,9 +20,24 @@
 #include <math.h>
 #include <fenv.h>
 #include <libm-alias-float.h>
+#include <math-narrow.h>
 #include <math-use-builtins.h>
 #include "math_config.h"
 
+#if !USE_FMAF_BUILTIN
+/* Narrow the double result to float.  The exact result of the fma is
+   representable as a double, so the conversion is the operation's single
+   rounding and it is what must signal underflow; help it where the
+   architecture does not.  */
+static inline float
+narrow_fmaf_result (double d)
+{
+  float ret = (float) d;
+  CHECK_NARROW_TINY (ret, d, __FLT_MIN__);
+  return ret;
+}
+#endif
+
 float
 __fmaf (float x, float y, float z)
 {
@@ -37,17 +52,17 @@ __fmaf (float x, float y, float z)
   /* If not exact or at round to even boundary, the result is correct in
      all rounding modes.  */
   if (__glibc_likely ((u & 0xfffffff) != 0))
-    return result;
+    return narrow_fmaf_result (result);
 
   /* Also check if the double result appears exact when it might not be and
      thus it will not set the underflow flag if denormal.  */
   if ((u & 0x10000000) == 0
       && ((u >> MANTISSA_WIDTH) & 0x7ff) > EXPONENT_BIAS - 126)
-    return result;
+    return narrow_fmaf_result (result);
 
   /* Return if result is exact in all rounding modes.  */
   if (result - xy == z && result - z == xy)
-    return result;
+    return narrow_fmaf_result (result);
 
   /* This is where 'double-rouding' might return a wrong value, and thus
      needs adjusting the low-order bits in the direction of the error.  */
@@ -62,7 +77,7 @@ __fmaf (float x, float y, float z)
     u++;
   else
     u--;
-  return asdouble (u);
+  return narrow_fmaf_result (asdouble (u));
 #endif /* ! USE_FMAF_BUILTIN  */
 }
 #ifndef __fmaf
-- 
2.54.0