Fix nexttoward overflow in non-default rounding modes (bug 19059).

ISO C requires overflowing results from nexttoward to be the
appropriate infinity independent of the rounding mode, but some
implementations use a rounding-mode-dependent result (this is the same
issue as was fixed for nextafter in bug 16677).  This patch fixes the
problem by making the nexttoward implementations discard the result
from the floating-point computation that forced an overflow exception
and then return the infinity previously computed with integer
arithmetic.

Tested for x86_64, x86, mips64 and powerpc.

	[BZ #19059]
	* math/s_nexttowardf.c (__nexttowardf): Do not return value from
	overflowing computation.
	* sysdeps/i386/fpu/s_nexttoward.c (__nexttoward): Likewise.
	* sysdeps/i386/fpu/s_nexttowardf.c (__nexttowardf): Likewise.
	* sysdeps/ieee754/ldbl-128/s_nexttoward.c (__nexttoward):
	Likewise.
	* sysdeps/ieee754/ldbl-128/s_nexttowardf.c (__nexttowardf):
	Likewise.
	* sysdeps/ieee754/ldbl-128ibm/s_nexttoward.c (__nexttoward):
	Likewise.
	* sysdeps/ieee754/ldbl-128ibm/s_nexttowardf.c (__nexttowardf):
	Likewise.
	* sysdeps/ieee754/ldbl-96/s_nexttoward.c (__nexttoward): Likewise.
	* sysdeps/ieee754/ldbl-96/s_nexttowardf.c (__nexttowardf):
	Likewise.
	* sysdeps/ieee754/ldbl-opt/s_nexttowardfd.c (__nldbl_nexttowardf):
	Likewise.
	* math/libm-test.inc (nexttoward_test_data): Add more tests.
This commit is contained in:
Joseph Myers 2015-10-02 17:11:13 +00:00
parent ef6b619f73
commit 59a63cca11
13 changed files with 47 additions and 20 deletions

View File

@ -1,5 +1,25 @@
2015-10-02 Joseph Myers <joseph@codesourcery.com> 2015-10-02 Joseph Myers <joseph@codesourcery.com>
[BZ #19059]
* math/s_nexttowardf.c (__nexttowardf): Do not return value from
overflowing computation.
* sysdeps/i386/fpu/s_nexttoward.c (__nexttoward): Likewise.
* sysdeps/i386/fpu/s_nexttowardf.c (__nexttowardf): Likewise.
* sysdeps/ieee754/ldbl-128/s_nexttoward.c (__nexttoward):
Likewise.
* sysdeps/ieee754/ldbl-128/s_nexttowardf.c (__nexttowardf):
Likewise.
* sysdeps/ieee754/ldbl-128ibm/s_nexttoward.c (__nexttoward):
Likewise.
* sysdeps/ieee754/ldbl-128ibm/s_nexttowardf.c (__nexttowardf):
Likewise.
* sysdeps/ieee754/ldbl-96/s_nexttoward.c (__nexttoward): Likewise.
* sysdeps/ieee754/ldbl-96/s_nexttowardf.c (__nexttowardf):
Likewise.
* sysdeps/ieee754/ldbl-opt/s_nexttowardfd.c (__nldbl_nexttowardf):
Likewise.
* math/libm-test.inc (nexttoward_test_data): Add more tests.
* nss/rewrite_field.c (__nss_rewrite_field): Use * nss/rewrite_field.c (__nss_rewrite_field): Use
internal_function. internal_function.
* nss/valid_field.c (__nss_valid_field): Likewise. * nss/valid_field.c (__nss_valid_field): Likewise.

2
NEWS
View File

@ -17,7 +17,7 @@ Version 2.23
18778, 18781, 18787, 18789, 18790, 18795, 18796, 18803, 18820, 18823, 18778, 18781, 18787, 18789, 18790, 18795, 18796, 18803, 18820, 18823,
18824, 18825, 18857, 18863, 18870, 18872, 18873, 18875, 18887, 18921, 18824, 18825, 18857, 18863, 18870, 18872, 18873, 18875, 18887, 18921,
18951, 18952, 18956, 18961, 18966, 18967, 18969, 18970, 18977, 18980, 18951, 18952, 18956, 18961, 18966, 18967, 18969, 18970, 18977, 18980,
18981, 18985, 19003, 19016, 19032, 19046. 18981, 18985, 19003, 19016, 19032, 19046, 19059.
* The obsolete header <regexp.h> has been removed. Programs that require * The obsolete header <regexp.h> has been removed. Programs that require
this header must be updated to use <regex.h> instead. this header must be updated to use <regex.h> instead.

View File

@ -8536,6 +8536,10 @@ static const struct test_ff_f_data_nexttoward nexttoward_test_data[] =
TEST_ff_f (nexttoward, 1.1L, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (nexttoward, 1.1L, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (nexttoward, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (nexttoward, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
/* Bug 6799: errno setting may be missing. */
TEST_ff_f (nexttoward, max_value, plus_infty, plus_infty, INEXACT_EXCEPTION|OVERFLOW_EXCEPTION),
TEST_ff_f (nexttoward, -max_value, minus_infty, minus_infty, INEXACT_EXCEPTION|OVERFLOW_EXCEPTION),
#ifdef TEST_FLOAT #ifdef TEST_FLOAT
TEST_ff_f (nexttoward, 1.0, 1.1L, 0x1.000002p0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (nexttoward, 1.0, 1.1L, 0x1.000002p0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_ff_f (nexttoward, 1.0, LDBL_MAX, 0x1.000002p0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (nexttoward, 1.0, LDBL_MAX, 0x1.000002p0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),

View File

@ -59,8 +59,8 @@ float __nexttowardf(float x, long double y)
} }
hy = hx&0x7f800000; hy = hx&0x7f800000;
if(hy>=0x7f800000) { if(hy>=0x7f800000) {
x = math_narrow_eval (x+x); /* overflow */ float u = x+x; /* overflow */
return x; math_force_eval (u);
} }
if(hy<0x00800000) { if(hy<0x00800000) {
float u = x*x; /* underflow */ float u = x*x; /* underflow */

View File

@ -73,8 +73,8 @@ double __nexttoward(double x, long double y)
} }
hy = hx&0x7ff00000; hy = hx&0x7ff00000;
if(hy>=0x7ff00000) { if(hy>=0x7ff00000) {
x = math_narrow_eval (x+x); /* overflow */ double u = x+x; /* overflow */
return x; math_force_eval (u);
} }
if(hy<0x00100000) { if(hy<0x00100000) {
double u = x*x; /* underflow */ double u = x*x; /* underflow */

View File

@ -61,8 +61,8 @@ float __nexttowardf(float x, long double y)
} }
hy = hx&0x7f800000; hy = hx&0x7f800000;
if(hy>=0x7f800000) { if(hy>=0x7f800000) {
x = math_narrow_eval (x+x); /* overflow */ float u = x+x; /* overflow */
return x; math_force_eval (u);
} }
if(hy<0x00800000) { if(hy<0x00800000) {
float u = x*x; /* underflow */ float u = x*x; /* underflow */

View File

@ -73,8 +73,8 @@ double __nexttoward(double x, long double y)
} }
hy = hx&0x7ff00000; hy = hx&0x7ff00000;
if(hy>=0x7ff00000) { if(hy>=0x7ff00000) {
x = math_narrow_eval (x+x); /* overflow */ double u = x+x; /* overflow */
return x; math_force_eval (u);
} }
if(hy<0x00100000) { if(hy<0x00100000) {
double u = x*x; /* underflow */ double u = x*x; /* underflow */

View File

@ -59,7 +59,10 @@ float __nexttowardf(float x, long double y)
} }
} }
hy = hx&0x7f800000; hy = hx&0x7f800000;
if(hy>=0x7f800000) return x+x; /* overflow */ if(hy>=0x7f800000) {
float u = x+x; /* overflow */
math_force_eval (u);
}
if(hy<0x00800000) { if(hy<0x00800000) {
float u = x*x; /* underflow */ float u = x*x; /* underflow */
math_force_eval (u); /* raise underflow flag */ math_force_eval (u); /* raise underflow flag */

View File

@ -74,8 +74,8 @@ double __nexttoward(double x, long double y)
} }
hy = hx&0x7ff00000; hy = hx&0x7ff00000;
if(hy>=0x7ff00000) { if(hy>=0x7ff00000) {
x = math_narrow_eval (x+x); /* overflow */ double u = x+x; /* overflow */
return x; math_force_eval (u);
} }
if(hy<0x00100000) { if(hy<0x00100000) {
double u = x*x; /* underflow */ double u = x*x; /* underflow */

View File

@ -63,8 +63,8 @@ float __nexttowardf(float x, long double y)
} }
hy = hx&0x7f800000; hy = hx&0x7f800000;
if(hy>=0x7f800000) { if(hy>=0x7f800000) {
x = math_narrow_eval (x+x); /* overflow */ float u = x+x; /* overflow */
return x; math_force_eval (u);
} }
if(hy<0x00800000) { /* underflow */ if(hy<0x00800000) { /* underflow */
float u = x*x; float u = x*x;

View File

@ -70,8 +70,8 @@ double __nexttoward(double x, long double y)
} }
hy = hx&0x7ff00000; hy = hx&0x7ff00000;
if(hy>=0x7ff00000) { if(hy>=0x7ff00000) {
x = math_narrow_eval (x+x); /* overflow */ double u = x+x; /* overflow */
return x; math_force_eval (u);
} }
if(hy<0x00100000) { if(hy<0x00100000) {
double u = x*x; /* underflow */ double u = x*x; /* underflow */

View File

@ -58,8 +58,8 @@ float __nexttowardf(float x, long double y)
} }
hy = hx&0x7f800000; hy = hx&0x7f800000;
if(hy>=0x7f800000) { if(hy>=0x7f800000) {
x = math_narrow_eval (x+x); /* overflow */ float u = x+x; /* overflow */
return x; math_force_eval (u);
} }
if(hy<0x00800000) { if(hy<0x00800000) {
float u = x*x; /* underflow */ float u = x*x; /* underflow */

View File

@ -62,8 +62,8 @@ float __nldbl_nexttowardf(float x, double y)
} }
hy = hx&0x7f800000; hy = hx&0x7f800000;
if(hy>=0x7f800000) { if(hy>=0x7f800000) {
x = math_narrow_eval (x+x); /* overflow */ float u = x+x; /* overflow */
return x; math_force_eval (u);
} }
if(hy<0x00800000) { if(hy<0x00800000) {
float u = x*x; /* underflow */ float u = x*x; /* underflow */