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:		3085fc9d97
This commit is contained in:
Steve Kargl
2026-06-07 21:12:16 +02:00
committed by Robert Clausecker
parent 4996ebdb72
commit c3f6dcea19
3 changed files with 27 additions and 22 deletions
+1 -1
View File
@@ -108,7 +108,7 @@ rsqrt(double x)
hx = (hx & 0x000fffff) | 0x3fe00000; hx = (hx & 0x000fffff) | 0x3fe00000;
SET_HIGH_WORD(x, hx); 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) { if (m & 1) {
x /= 2; x /= 2;
m += 1; m += 1;
+20 -13
View File
@@ -108,7 +108,7 @@ rsqrtf(float x)
ix = (ix & 0x007fffff) | 0x3f000000; ix = (ix & 0x007fffff) | 0x3f000000;
SET_FLOAT_WORD(x, ix); /* x is in [0.5,1). */ 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) { if (m & 1) {
x /= 2; x /= 2;
m += 1; m += 1;
@@ -122,32 +122,39 @@ rsqrtf(float x)
* a max ulp of ~1.49. * a max ulp of ~1.49.
*/ */
y = 1 / sqrtf(x); y = 1 / sqrtf(x);
h = y / 2; h = y / 2;
/* /*
* For values of x with a representation of 0x1.fffffcpN with * For values of x with representations of the forms 0x1.fffffcpN
* N an odd integer, the computed rsqrtf() is not correctly * or 0x1.13e07pN with N an odd integer, the computed rsqrtf() is
* rounded in round-to-nearest without toggling the rounding * not correctly rounded in round-to-nearest without fiddling with
* mode to FE_TOWARDZERO. Note, FE_DOWNWARD also works. * the rounding mode and/or bits of x.
* However, messing with the rounding mode is expensive, so
* only do it when necessary. Example, x = 0x1.fffffcp3 gives
* y --> 0x3f800001.
*/ */
GET_FLOAT_WORD(ix, y); GET_FLOAT_WORD(ix, y);
if ((ix & 0x000fffff) == 1) { if ((ix & 0x000fffff) == 1) { /* 0x1.fffffcpN */
rnd = fegetround(); rnd = fegetround();
fesetround(FE_TOWARDZERO); fesetround(FE_DOWNWARD);
_MUL(x, y, zh, zl); _MUL(x, y, zh, zl);
_XMUL(zh, zl, h, 0, ph, pl); _XMUL(zh, zl, h, 0, ph, pl);
fesetround(rnd); 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_DOWNWARD);
_MUL(x, y, zh, zl);
_XMUL(zh, zl, h, 0, ph, pl);
_XADD(-ph, -pl, half, 0, rh, rl);
y = h + h * rh;
fesetround(rnd);
} else { } else {
_MUL(x, y, zh, zl); _MUL(x, y, zh, zl);
_XMUL(zh, zl, h, 0, ph, pl); _XMUL(zh, zl, h, 0, ph, pl);
}
_XADD(-ph, -pl, half, 0, rh, rl); _XADD(-ph, -pl, half, 0, rh, rl);
y = h * rh + h; y = h * rh + h;
}
ix = (uint32_t)(m + 128) << 23; ix = (uint32_t)(m + 128) << 23;
SET_FLOAT_WORD(x, ix); SET_FLOAT_WORD(x, ix);
+3 -5
View File
@@ -108,7 +108,7 @@ rsqrtl(long double x)
} }
u.bits.exp = 0x3ffe; 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) { if (m & 1) {
u.e /= 2; u.e /= 2;
m += 1; m += 1;
@@ -141,8 +141,9 @@ long double
rsqrtl(long double x) rsqrtl(long double x)
{ {
volatile static const double vzero = 0; volatile static const double vzero = 0;
static const double half = 0.5;
int hx, m, rnd; int hx, m, rnd;
long double y; long double h, ph, pl, rh, rl, y, zh, zl;
/* x = +-0. Raise exception. */ /* x = +-0. Raise exception. */
if (x == 0) if (x == 0)
@@ -183,9 +184,6 @@ rsqrtl(long double x)
y = 1 / sqrt((double)x); /* ~52-bit estimate. */ y = 1 / sqrt((double)x); /* ~52-bit estimate. */
y -= y * (x * y * y - 1) / 2; /* ~104-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; h = y / 2;
rnd = fegetround(); rnd = fegetround();