1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

Correct IBM long double nextafterl.

Fix for values near a power of two, and some tidies.

	[BZ #16739]
	* sysdeps/ieee754/ldbl-128ibm/s_nextafterl.c (__nextafterl): Correct
	output when value is near a power of two.  Use int64_t for lx and
	remove casts.  Use decimal rather than hex exponent constants.
	Don't use long double multiplication when double will suffice.
	* math/libm-test.inc (nextafter_test_data): Add tests.
	* NEWS: Add 16739 and 16786 to bug list.
This commit is contained in:
Alan Modra
2014-04-02 13:46:19 +10:30
parent af6b17973c
commit b0abbc2103
4 changed files with 52 additions and 17 deletions

View File

@ -1,3 +1,13 @@
2014-04-02 Alan Modra <amodra@gmail.com>
[BZ #16739]
* sysdeps/ieee754/ldbl-128ibm/s_nextafterl.c (__nextafterl): Correct
output when value is near a power of two. Use int64_t for lx and
remove casts. Use decimal rather than hex exponent constants.
Don't use long double multiplication when double will suffice.
* math/libm-test.inc (nextafter_test_data): Add tests.
* NEWS: Add 16739 and 16786 to bug list.
2014-04-02 Alan Modra <amodra@gmail.com> 2014-04-02 Alan Modra <amodra@gmail.com>
* sysdeps/powerpc/powerpc64/power7/memrchr.S: Correct stream hint. * sysdeps/powerpc/powerpc64/power7/memrchr.S: Correct stream hint.

2
NEWS
View File

@ -13,7 +13,7 @@ Version 2.20
16357, 16362, 16447, 16532, 16545, 16574, 16599, 16600, 16609, 16610, 16357, 16362, 16447, 16532, 16545, 16574, 16599, 16600, 16609, 16610,
16611, 16613, 16623, 16632, 16634, 16639, 16642, 16648, 16649, 16670, 16611, 16613, 16623, 16632, 16634, 16639, 16642, 16648, 16649, 16670,
16674, 16677, 16680, 16683, 16689, 16695, 16701, 16706, 16707, 16712, 16674, 16677, 16680, 16683, 16689, 16695, 16701, 16706, 16707, 16712,
16713, 16714, 16731, 16743, 16758, 16759, 16760, 16770. 16713, 16714, 16731, 16739, 16743, 16758, 16759, 16760, 16770, 16786.
* Running the testsuite no longer terminates as soon as a test fails. * Running the testsuite no longer terminates as soon as a test fails.
Instead, a file tests.sum (xtests.sum from "make xcheck") is generated, Instead, a file tests.sum (xtests.sum from "make xcheck") is generated,

View File

@ -8302,6 +8302,14 @@ static const struct test_ff_f_data nextafter_test_data[] =
// XXX Enable once gcc is fixed. // XXX Enable once gcc is fixed.
//TEST_ff_f (nextafter, 0x0.00000040000000000000p-16385L, -0.1L, 0x0.0000003ffffffff00000p-16385L), //TEST_ff_f (nextafter, 0x0.00000040000000000000p-16385L, -0.1L, 0x0.0000003ffffffff00000p-16385L),
#endif #endif
#if defined TEST_LDOUBLE && LDBL_MANT_DIG == 106
TEST_ff_f (nextafter, 1.0L, -10.0L, 1.0L-0x1p-106L, NO_EXCEPTION),
TEST_ff_f (nextafter, 1.0L, 10.0L, 1.0L+0x1p-105L, NO_EXCEPTION),
TEST_ff_f (nextafter, 1.0L-0x1p-106L, 10.0L, 1.0L, NO_EXCEPTION),
TEST_ff_f (nextafter, -1.0L, -10.0L, -1.0L-0x1p-105L, NO_EXCEPTION),
TEST_ff_f (nextafter, -1.0L, 10.0L, -1.0L+0x1p-106L, NO_EXCEPTION),
TEST_ff_f (nextafter, -1.0L+0x1p-106L, -10.0L, -1.0L, NO_EXCEPTION),
#endif
/* XXX We need the hexadecimal FP number representation here for further /* XXX We need the hexadecimal FP number representation here for further
tests. */ tests. */

View File

@ -30,8 +30,7 @@ static char rcsid[] = "$NetBSD: $";
long double __nextafterl(long double x, long double y) long double __nextafterl(long double x, long double y)
{ {
int64_t hx,hy,ihx,ihy; int64_t hx, hy, ihx, ihy, lx;
uint64_t lx;
double xhi, xlo, yhi; double xhi, xlo, yhi;
ldbl_unpack (x, &xhi, &xlo); ldbl_unpack (x, &xhi, &xlo);
@ -79,19 +78,28 @@ long double __nextafterl(long double x, long double y)
u = math_opt_barrier (x); u = math_opt_barrier (x);
x -= __LDBL_DENORM_MIN__; x -= __LDBL_DENORM_MIN__;
if (ihx < 0x0360000000000000LL if (ihx < 0x0360000000000000LL
|| (hx > 0 && (int64_t) lx <= 0) || (hx > 0 && lx <= 0)
|| (hx < 0 && (int64_t) lx > 1)) { || (hx < 0 && lx > 1)) {
u = u * u; u = u * u;
math_force_eval (u); /* raise underflow flag */ math_force_eval (u); /* raise underflow flag */
} }
return x; return x;
} }
if (ihx < 0x06a0000000000000LL) { /* ulp will denormal */ /* If the high double is an exact power of two and the low
INSERT_WORDS64 (yhi, hx & (0x7ffLL<<52)); double is the opposite sign, then 1ulp is one less than
u = yhi; what we might determine from the high double. Similarly
u *= 0x1.0000000000000p-105L; if X is an exact power of two, and positive, because
making it a little smaller will result in the exponent
decreasing by one and normalisation of the mantissa. */
if ((hx & 0x000fffffffffffffLL) == 0
&& ((lx != 0 && (hx ^ lx) < 0)
|| (lx == 0 && hx >= 0)))
ihx -= 1LL << 52;
if (ihx < (106LL << 52)) { /* ulp will denormal */
INSERT_WORDS64 (yhi, ihx & (0x7ffLL<<52));
u = yhi * 0x1p-105;
} else { } else {
INSERT_WORDS64 (yhi, (hx & (0x7ffLL<<52))-(0x069LL<<52)); INSERT_WORDS64 (yhi, (ihx & (0x7ffLL<<52))-(105LL<<52));
u = yhi; u = yhi;
} }
return x - u; return x - u;
@ -109,8 +117,8 @@ long double __nextafterl(long double x, long double y)
u = math_opt_barrier (x); u = math_opt_barrier (x);
x += __LDBL_DENORM_MIN__; x += __LDBL_DENORM_MIN__;
if (ihx < 0x0360000000000000LL if (ihx < 0x0360000000000000LL
|| (hx > 0 && (int64_t) lx < 0 && lx != 0x8000000000000001LL) || (hx > 0 && lx < 0 && lx != 0x8000000000000001LL)
|| (hx < 0 && (int64_t) lx >= 0)) { || (hx < 0 && lx >= 0)) {
u = u * u; u = u * u;
math_force_eval (u); /* raise underflow flag */ math_force_eval (u); /* raise underflow flag */
} }
@ -118,12 +126,21 @@ long double __nextafterl(long double x, long double y)
x = -0.0L; x = -0.0L;
return x; return x;
} }
if (ihx < 0x06a0000000000000LL) { /* ulp will denormal */ /* If the high double is an exact power of two and the low
INSERT_WORDS64 (yhi, hx & (0x7ffLL<<52)); double is the opposite sign, then 1ulp is one less than
u = yhi; what we might determine from the high double. Similarly
u *= 0x1.0000000000000p-105L; if X is an exact power of two, and negative, because
making it a little larger will result in the exponent
decreasing by one and normalisation of the mantissa. */
if ((hx & 0x000fffffffffffffLL) == 0
&& ((lx != 0 && (hx ^ lx) < 0)
|| (lx == 0 && hx < 0)))
ihx -= 1LL << 52;
if (ihx < (106LL << 52)) { /* ulp will denormal */
INSERT_WORDS64 (yhi, ihx & (0x7ffLL<<52));
u = yhi * 0x1p-105;
} else { } else {
INSERT_WORDS64 (yhi, (hx & (0x7ffLL<<52))-(0x069LL<<52)); INSERT_WORDS64 (yhi, (ihx & (0x7ffLL<<52))-(105LL<<52));
u = yhi; u = yhi;
} }
return x + u; return x + u;