summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2015-10-02 17:11:13 +0000
committerJoseph Myers <joseph@codesourcery.com>2015-10-02 17:11:13 +0000
commit59a63cca1133a8e1e3219970ee95979ac1f810df (patch)
treea4fc7c389f60647377479748d75bcc94f3c36547
parentef6b619f73e49b6d87c7530e6e9f8a59723b492d (diff)
downloadglibc-59a63cca1133a8e1e3219970ee95979ac1f810df.tar.gz
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.
-rw-r--r--ChangeLog20
-rw-r--r--NEWS2
-rw-r--r--math/libm-test.inc4
-rw-r--r--math/s_nexttowardf.c4
-rw-r--r--sysdeps/i386/fpu/s_nexttoward.c4
-rw-r--r--sysdeps/i386/fpu/s_nexttowardf.c4
-rw-r--r--sysdeps/ieee754/ldbl-128/s_nexttoward.c4
-rw-r--r--sysdeps/ieee754/ldbl-128/s_nexttowardf.c5
-rw-r--r--sysdeps/ieee754/ldbl-128ibm/s_nexttoward.c4
-rw-r--r--sysdeps/ieee754/ldbl-128ibm/s_nexttowardf.c4
-rw-r--r--sysdeps/ieee754/ldbl-96/s_nexttoward.c4
-rw-r--r--sysdeps/ieee754/ldbl-96/s_nexttowardf.c4
-rw-r--r--sysdeps/ieee754/ldbl-opt/s_nexttowardfd.c4
13 files changed, 47 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index 51476e6979..e03132aeba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
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
internal_function.
* nss/valid_field.c (__nss_valid_field): Likewise.
diff --git a/NEWS b/NEWS
index 4634b74ebf..05d962221b 100644
--- a/NEWS
+++ b/NEWS
@@ -17,7 +17,7 @@ Version 2.23
18778, 18781, 18787, 18789, 18790, 18795, 18796, 18803, 18820, 18823,
18824, 18825, 18857, 18863, 18870, 18872, 18873, 18875, 18887, 18921,
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
this header must be updated to use <regex.h> instead.
diff --git a/math/libm-test.inc b/math/libm-test.inc
index f627296d66..ac1fe85fc1 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -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, 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
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),
diff --git a/math/s_nexttowardf.c b/math/s_nexttowardf.c
index 06e1bb10cb..06350d47bf 100644
--- a/math/s_nexttowardf.c
+++ b/math/s_nexttowardf.c
@@ -59,8 +59,8 @@ float __nexttowardf(float x, long double y)
}
hy = hx&0x7f800000;
if(hy>=0x7f800000) {
- x = math_narrow_eval (x+x); /* overflow */
- return x;
+ float u = x+x; /* overflow */
+ math_force_eval (u);
}
if(hy<0x00800000) {
float u = x*x; /* underflow */
diff --git a/sysdeps/i386/fpu/s_nexttoward.c b/sysdeps/i386/fpu/s_nexttoward.c
index be65b8ce29..839efe6c05 100644
--- a/sysdeps/i386/fpu/s_nexttoward.c
+++ b/sysdeps/i386/fpu/s_nexttoward.c
@@ -73,8 +73,8 @@ double __nexttoward(double x, long double y)
}
hy = hx&0x7ff00000;
if(hy>=0x7ff00000) {
- x = math_narrow_eval (x+x); /* overflow */
- return x;
+ double u = x+x; /* overflow */
+ math_force_eval (u);
}
if(hy<0x00100000) {
double u = x*x; /* underflow */
diff --git a/sysdeps/i386/fpu/s_nexttowardf.c b/sysdeps/i386/fpu/s_nexttowardf.c
index 8379eff8b8..29b4f12775 100644
--- a/sysdeps/i386/fpu/s_nexttowardf.c
+++ b/sysdeps/i386/fpu/s_nexttowardf.c
@@ -61,8 +61,8 @@ float __nexttowardf(float x, long double y)
}
hy = hx&0x7f800000;
if(hy>=0x7f800000) {
- x = math_narrow_eval (x+x); /* overflow */
- return x;
+ float u = x+x; /* overflow */
+ math_force_eval (u);
}
if(hy<0x00800000) {
float u = x*x; /* underflow */
diff --git a/sysdeps/ieee754/ldbl-128/s_nexttoward.c b/sysdeps/ieee754/ldbl-128/s_nexttoward.c
index e62ca3fef8..2ee7a1be5c 100644
--- a/sysdeps/ieee754/ldbl-128/s_nexttoward.c
+++ b/sysdeps/ieee754/ldbl-128/s_nexttoward.c
@@ -73,8 +73,8 @@ double __nexttoward(double x, long double y)
}
hy = hx&0x7ff00000;
if(hy>=0x7ff00000) {
- x = math_narrow_eval (x+x); /* overflow */
- return x;
+ double u = x+x; /* overflow */
+ math_force_eval (u);
}
if(hy<0x00100000) {
double u = x*x; /* underflow */
diff --git a/sysdeps/ieee754/ldbl-128/s_nexttowardf.c b/sysdeps/ieee754/ldbl-128/s_nexttowardf.c
index ccd49d235d..9c9c7e5283 100644
--- a/sysdeps/ieee754/ldbl-128/s_nexttowardf.c
+++ b/sysdeps/ieee754/ldbl-128/s_nexttowardf.c
@@ -59,7 +59,10 @@ float __nexttowardf(float x, long double y)
}
}
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) {
float u = x*x; /* underflow */
math_force_eval (u); /* raise underflow flag */
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_nexttoward.c b/sysdeps/ieee754/ldbl-128ibm/s_nexttoward.c
index 85140c1d02..8c6119825e 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_nexttoward.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_nexttoward.c
@@ -74,8 +74,8 @@ double __nexttoward(double x, long double y)
}
hy = hx&0x7ff00000;
if(hy>=0x7ff00000) {
- x = math_narrow_eval (x+x); /* overflow */
- return x;
+ double u = x+x; /* overflow */
+ math_force_eval (u);
}
if(hy<0x00100000) {
double u = x*x; /* underflow */
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_nexttowardf.c b/sysdeps/ieee754/ldbl-128ibm/s_nexttowardf.c
index b27f0bb380..4000a93e69 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_nexttowardf.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_nexttowardf.c
@@ -63,8 +63,8 @@ float __nexttowardf(float x, long double y)
}
hy = hx&0x7f800000;
if(hy>=0x7f800000) {
- x = math_narrow_eval (x+x); /* overflow */
- return x;
+ float u = x+x; /* overflow */
+ math_force_eval (u);
}
if(hy<0x00800000) { /* underflow */
float u = x*x;
diff --git a/sysdeps/ieee754/ldbl-96/s_nexttoward.c b/sysdeps/ieee754/ldbl-96/s_nexttoward.c
index b972a3eb3a..7908f9c0ff 100644
--- a/sysdeps/ieee754/ldbl-96/s_nexttoward.c
+++ b/sysdeps/ieee754/ldbl-96/s_nexttoward.c
@@ -70,8 +70,8 @@ double __nexttoward(double x, long double y)
}
hy = hx&0x7ff00000;
if(hy>=0x7ff00000) {
- x = math_narrow_eval (x+x); /* overflow */
- return x;
+ double u = x+x; /* overflow */
+ math_force_eval (u);
}
if(hy<0x00100000) {
double u = x*x; /* underflow */
diff --git a/sysdeps/ieee754/ldbl-96/s_nexttowardf.c b/sysdeps/ieee754/ldbl-96/s_nexttowardf.c
index f1fe4e7ca7..53c527d9ac 100644
--- a/sysdeps/ieee754/ldbl-96/s_nexttowardf.c
+++ b/sysdeps/ieee754/ldbl-96/s_nexttowardf.c
@@ -58,8 +58,8 @@ float __nexttowardf(float x, long double y)
}
hy = hx&0x7f800000;
if(hy>=0x7f800000) {
- x = math_narrow_eval (x+x); /* overflow */
- return x;
+ float u = x+x; /* overflow */
+ math_force_eval (u);
}
if(hy<0x00800000) {
float u = x*x; /* underflow */
diff --git a/sysdeps/ieee754/ldbl-opt/s_nexttowardfd.c b/sysdeps/ieee754/ldbl-opt/s_nexttowardfd.c
index 782e1a3340..dbcf840f2c 100644
--- a/sysdeps/ieee754/ldbl-opt/s_nexttowardfd.c
+++ b/sysdeps/ieee754/ldbl-opt/s_nexttowardfd.c
@@ -62,8 +62,8 @@ float __nldbl_nexttowardf(float x, double y)
}
hy = hx&0x7f800000;
if(hy>=0x7f800000) {
- x = math_narrow_eval (x+x); /* overflow */
- return x;
+ float u = x+x; /* overflow */
+ math_force_eval (u);
}
if(hy<0x00800000) {
float u = x*x; /* underflow */