git: c3f6dcea1992 - main - msun: Fix up for recent rsqrt[fl] functions

From: Robert Clausecker <fuz_at_FreeBSD.org>
Date: Sun, 07 Jun 2026 21:00:58 UTC
The branch main has been updated by fuz:

URL: https://cgit.FreeBSD.org/src/commit/?id=c3f6dcea199289329c1d3b91b69e5a4821fc3dff

commit c3f6dcea199289329c1d3b91b69e5a4821fc3dff
Author:     Steve Kargl <kargl@FreeBSD.org>
AuthorDate: 2026-06-07 19:12:16 +0000
Commit:     Robert Clausecker <fuz@FreeBSD.org>
CommitDate: 2026-06-07 20:59:19 +0000

    msun: Fix up for recent rsqrt[fl] functions
    
    Paul Zimmermann (of Core-Math and MPFR fame) graciously tested
    the recently committed rsqrt[fl]() functions.  He identified 127
    incorrectly rounded values for rsqrtf() in round-to-nearest mode.
    This patch fixes the rounding in RN.  Exhaustive testing now shows
    that rsqrtf() is corrected rounded for RN.  He also tested rsqrt()
    and rsqrtl() in the interval [1,4).  Both appear to be correctly
    rounded.  Finally, the patch includes small changes to comments.
    
    A concise list of changes is
    
    * lib/msun/src/s_rsqrt.c:
      . Fix comments.
    
    * lib/msun/src/s_rsqrtf.c
      . Fix comments.
      . Exhaustive testing by Paul Zimmermann found 127 incorrectly
        rounded values in round-to-nearests.  These gave have the
        form 0x1.13e07pN with N an odd integer.  With this patch, all
        values are now correctly rounded in round-to-nearest.
    
    * lib/msun/src/s_rsqrtl.c
       . Fix comments.
       . Move all variable declarations to top of function and sort.
    
    PR:             295706
    MFC after:      1 week
    Fixes:          3085fc9d97bd83785ba3ba43e0378d7d67987d1f
---
 lib/msun/src/s_rsqrt.c  |  4 ++--
 lib/msun/src/s_rsqrtf.c | 37 ++++++++++++++++++++++---------------
 lib/msun/src/s_rsqrtl.c |  8 +++-----
 3 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/lib/msun/src/s_rsqrt.c b/lib/msun/src/s_rsqrt.c
index 0a513afe8ed2..cac16f837a05 100644
--- a/lib/msun/src/s_rsqrt.c
+++ b/lib/msun/src/s_rsqrt.c
@@ -108,14 +108,14 @@ rsqrt(double x)
 	hx = (hx & 0x000fffff) | 0x3fe00000;
 	SET_HIGH_WORD(x, hx);
 
-	/* m is odd.  Put x into [0.25,5) and increase m. */
+	/* m is odd.  Put x into [0.25,0.5) and increase m. */
 	if (m & 1) {
 	    x /= 2;
 	    m += 1;
 	}
 	m = -(m >> 1);			/* Prepare for 2^(-m/2). */
 
-	y = 1 / sqrt(x);	/* ~52-bit estimate. */
+	y = 1 / sqrt(x);		/* ~52-bit estimate. */
 
 	h = y / 2;
 
diff --git a/lib/msun/src/s_rsqrtf.c b/lib/msun/src/s_rsqrtf.c
index b71f7baf5657..faeb1c300e18 100644
--- a/lib/msun/src/s_rsqrtf.c
+++ b/lib/msun/src/s_rsqrtf.c
@@ -108,7 +108,7 @@ rsqrtf(float x)
 	ix = (ix & 0x007fffff) | 0x3f000000;
 	SET_FLOAT_WORD(x, ix);		/* x is in [0.5,1). */
 
-	/* m is odd.  Put x into [0.25,5) and increase m. */
+	/* m is odd.  Put x into [0.25,0.5) and increase m. */
 	if (m & 1) {
 	    x /= 2;
 	    m += 1;
@@ -122,33 +122,40 @@ rsqrtf(float x)
 	 * a max ulp of ~1.49.
 	 */
 	y = 1 / sqrtf(x);
-
 	h = y / 2;
 
 	/*
-	 * For values of x with a representation of 0x1.fffffcpN with
-	 * N an odd integer, the computed rsqrtf() is not correctly
-	 * rounded in round-to-nearest without toggling the rounding
-	 * mode  to FE_TOWARDZERO.  Note, FE_DOWNWARD also works.
-	 * However, messing with the rounding mode is expensive, so
-	 * only do it when necessary. Example, x = 0x1.fffffcp3 gives
-	 * y --> 0x3f800001.
+	 * For values of x with representations of the forms 0x1.fffffcpN
+	 * or 0x1.13e07pN with N an odd integer, the computed rsqrtf() is
+	 * not correctly rounded in round-to-nearest without fiddling with
+	 * the rounding mode and/or bits of x.
 	 */
 	GET_FLOAT_WORD(ix, y);
-	if ((ix & 0x000fffff) == 1) {
+	if ((ix & 0x000fffff) == 1) {			/* 0x1.fffffcpN */
+	    rnd = fegetround();
+	    fesetround(FE_DOWNWARD);
+	    _MUL(x, y, zh, zl);
+	    _XMUL(zh, zl, h, 0, ph, pl);
+	    fesetround(rnd);
+            _XADD(-ph, -pl, half, 0, rh, rl);
+            y = h + h * rh;
+	} else if((ix & 0x00ffffff) == 0x00ae6055) {	/* 0x1.13e07pN */
+	    GET_FLOAT_WORD(ix, x);
+	    SET_FLOAT_WORD(x, ix - 1);
 	    rnd = fegetround();
-	    fesetround(FE_TOWARDZERO);
+	    fesetround(FE_DOWNWARD);
 	    _MUL(x, y, zh, zl);
 	    _XMUL(zh, zl, h, 0, ph, pl);
-	   fesetround(rnd);
+            _XADD(-ph, -pl, half, 0, rh, rl);
+            y = h + h * rh;
+	    fesetround(rnd);
 	} else {
 	    _MUL(x, y, zh, zl);
 	    _XMUL(zh, zl, h, 0, ph, pl);
+	    _XADD(-ph, -pl, half, 0, rh, rl);
+	    y = h * rh + h;
 	}
 
-	_XADD(-ph, -pl, half, 0, rh, rl);
-	y = h * rh + h;
-
 	ix = (uint32_t)(m + 128) << 23;
 	SET_FLOAT_WORD(x, ix);
 	return (y *= x);
diff --git a/lib/msun/src/s_rsqrtl.c b/lib/msun/src/s_rsqrtl.c
index 34d5cdc48173..bf3d32481e3f 100644
--- a/lib/msun/src/s_rsqrtl.c
+++ b/lib/msun/src/s_rsqrtl.c
@@ -108,7 +108,7 @@ rsqrtl(long double x)
 	}
 	u.bits.exp = 0x3ffe;
 
-	/* m is odd.  Put x into [0.25,5) and increase m. */
+	/* m is odd.  Put x into [0.25,0.5) and increase m. */
 	if (m & 1) {
 	    u.e /= 2;
 	    m += 1;
@@ -141,8 +141,9 @@ long double
 rsqrtl(long double x)
 {
 	volatile static const double vzero = 0;
+	static const double half = 0.5;
 	int hx, m, rnd;
-	long double y;
+	long double h, ph, pl, rh, rl, y, zh, zl;
 
 	/* x = +-0.  Raise exception. */
 	if (x == 0)
@@ -183,9 +184,6 @@ rsqrtl(long double x)
 	y = 1 / sqrt((double)x);	/* ~52-bit estimate. */
 	y -= y * (x * y * y - 1) / 2;	/* ~104-bit estimate. */
 
-	static const double half = 0.5;
-	long double h, ph, pl, rh, rl, zh, zl;
-
 	h = y / 2;
 
 	rnd = fegetround();