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:
committed by
Robert Clausecker
parent
4996ebdb72
commit
c3f6dcea19
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user