]> sourceware.org Git - glibc.git/commitdiff
Fix lround, llround missing exceptions close to overflow threshold (bug 19088).
authorJoseph Myers <joseph@codesourcery.com>
Wed, 7 Oct 2015 23:45:29 +0000 (23:45 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Wed, 7 Oct 2015 23:45:29 +0000 (23:45 +0000)
The dbl-64, ldbl-96 and ldbl-128 implementations of lround and llround
fail to produce "invalid" exceptions in cases where the rounded result
overflows the target type, but truncating the floating-point argument
to the next integer towards zero does not overflow it (so in
particular casts do not produce such exceptions).  (This issue cannot
arise for float, or for double with 64-bit target type, or for ldbl-96
with 64-bit target type and negative arguments, because of
insufficient precision in the floating-point type for arguments with
the relevant property to exist.)

This patch fixes these problems by inserting checks for the special
cases that can occur in each implementation, and explicitly raising
FE_INVALID (and avoiding the cast if it might raise spurious
FE_INEXACT).

Tested for x86_64, x86 and mips64.

[BZ #19088]
* sysdeps/ieee754/dbl-64/s_lround.c: Include <fenv.h> and
<limits.h>.
(__lround) [FE_INVALID]: Force FE_INVALID exception when result
overflows but exception would not result from cast.
* sysdeps/ieee754/dbl-64/wordsize-64/s_lround.c: Include <fenv.h>
and <limits.h>.
(__lround) [FE_INVALID]: Force FE_INVALID exception when result
overflows but exception would not result from cast.
* sysdeps/ieee754/ldbl-128/s_llroundl.c: Include <fenv.h> and
<limits.h>.
(__llroundl) [FE_INVALID]: Force FE_INVALID exception when result
overflows but exception would not result from cast.
* sysdeps/ieee754/ldbl-128/s_lroundl.c: Include <fenv.h> and
<limits.h>.
(__lroundl) [FE_INVALID]: Force FE_INVALID exception when result
overflows but exception would not result from cast.
* sysdeps/ieee754/ldbl-96/s_llroundl.c: Include <fenv.h> and
<limits.h>.
(__llroundl) [FE_INVALID]: Force FE_INVALID exception when result
overflows but exception would not result from cast.
* sysdeps/ieee754/ldbl-96/s_lroundl.c: Include <fenv.h> and
<limits.h>.
(__lroundl) [FE_INVALID]: Force FE_INVALID exception when result
overflows but exception would not result from cast.
* math/libm-test.inc (lround_test_data): Add more tests.
(llround_test_data): Likewise.

ChangeLog
NEWS
math/libm-test.inc
sysdeps/ieee754/dbl-64/s_lround.c
sysdeps/ieee754/dbl-64/wordsize-64/s_lround.c
sysdeps/ieee754/ldbl-128/s_llroundl.c
sysdeps/ieee754/ldbl-128/s_lroundl.c
sysdeps/ieee754/ldbl-96/s_llroundl.c
sysdeps/ieee754/ldbl-96/s_lroundl.c

index 58069c75a2f744c39aad08dbbc7ead300df3a8bb..821168246e4642f9319bc41e5d6edc0dd68bdcfd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+2015-10-07  Joseph Myers  <joseph@codesourcery.com>
+
+       [BZ #19088]
+       * sysdeps/ieee754/dbl-64/s_lround.c: Include <fenv.h> and
+       <limits.h>.
+       (__lround) [FE_INVALID]: Force FE_INVALID exception when result
+       overflows but exception would not result from cast.
+       * sysdeps/ieee754/dbl-64/wordsize-64/s_lround.c: Include <fenv.h>
+       and <limits.h>.
+       (__lround) [FE_INVALID]: Force FE_INVALID exception when result
+       overflows but exception would not result from cast.
+       * sysdeps/ieee754/ldbl-128/s_llroundl.c: Include <fenv.h> and
+       <limits.h>.
+       (__llroundl) [FE_INVALID]: Force FE_INVALID exception when result
+       overflows but exception would not result from cast.
+       * sysdeps/ieee754/ldbl-128/s_lroundl.c: Include <fenv.h> and
+       <limits.h>.
+       (__lroundl) [FE_INVALID]: Force FE_INVALID exception when result
+       overflows but exception would not result from cast.
+       * sysdeps/ieee754/ldbl-96/s_llroundl.c: Include <fenv.h> and
+       <limits.h>.
+       (__llroundl) [FE_INVALID]: Force FE_INVALID exception when result
+       overflows but exception would not result from cast.
+       * sysdeps/ieee754/ldbl-96/s_lroundl.c: Include <fenv.h> and
+       <limits.h>.
+       (__lroundl) [FE_INVALID]: Force FE_INVALID exception when result
+       overflows but exception would not result from cast.
+       * math/libm-test.inc (lround_test_data): Add more tests.
+       (llround_test_data): Likewise.
+
 2015-10-07  Steve Ellcey  <sellcey@imgtec.com>
 
        * timezone/Makefile (CFLAGS-zic.c): Add -Wno-unused-variable.
diff --git a/NEWS b/NEWS
index 30284ba6a33e3e858011b8dabbc0ba5958f8f860..a3adcfdff810cafb65975f93f4484c8c67810487 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -18,7 +18,7 @@ Version 2.23
   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, 19012, 19016, 19018, 19032, 19046,
-  19049, 19050, 19059, 19071, 19076, 19077, 19078, 19079, 19085.
+  19049, 19050, 19059, 19071, 19076, 19077, 19078, 19079, 19085, 19088.
 
 * The obsolete header <regexp.h> has been removed.  Programs that require
   this header must be updated to use <regex.h> instead.
index 54f62f8a32ce46eeb9fce7847d24416e358f2f53..fe74e28e34bde07fa58a0a2a95b54c46d241a844 100644 (file)
@@ -8282,6 +8282,123 @@ static const struct test_f_l_data lround_test_data[] =
 #endif
     TEST_f_l (lround, -0x1p64, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
     TEST_f_l (lround, -0x1p65, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lround, 0x7fffff80p0, 0x7fffff80LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#ifndef TEST_FLOAT
+    TEST_f_l (lround, 0x7fffffffp0, 0x7fffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_l (lround, 0x7fffffff.4p0, 0x7fffffffLL, ERRNO_UNCHANGED),
+    TEST_f_l (lround, 0x7fffffff.7ffffcp0, 0x7fffffffLL, ERRNO_UNCHANGED),
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lround, 0x7fffffff.8p0, 0x80000000LL, ERRNO_UNCHANGED),
+    TEST_f_l (lround, 0x7fffffff.cp0, 0x80000000LL, ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lround, 0x7fffffff.8p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lround, 0x7fffffff.cp0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64
+    TEST_f_l (lround, 0x7fffffff.7fffffff8p0L, 0x7fffffffLL, ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_l (lround, 0x7fffffff.7fffffffffffffffffep0L, 0x7fffffffLL, ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_l (lround, 0x7fffffff.7fffffffffffffffffffcp0L, 0x7fffffffLL, ERRNO_UNCHANGED),
+#endif
+#ifndef TEST_FLOAT
+    TEST_f_l (lround, -0x80000000.4p0, -0x80000000LL, ERRNO_UNCHANGED),
+    TEST_f_l (lround, -0x80000000.7ffff8p0, -0x80000000LL, ERRNO_UNCHANGED),
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lround, -0x80000000.8p0, -0x80000001LL, ERRNO_UNCHANGED),
+    TEST_f_l (lround, -0x80000000.cp0, -0x80000001LL, ERRNO_UNCHANGED),
+    TEST_f_l (lround, -0x80000001p0, -0x80000001LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lround, -0x80000000.8p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lround, -0x80000000.cp0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lround, -0x80000001p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
+#if LONG_MAX > 0x7fffffff
+    TEST_f_l (lround, -0x80000100p0, -0x80000100LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#else
+    TEST_f_l (lround, -0x80000100p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64
+    TEST_f_l (lround, -0x80000000.7fffffffp0L, -0x80000000LL, ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_l (lround, -0x80000000.7fffffffffffffffffcp0L, -0x80000000LL, ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_l (lround, -0x80000000.7fffffffffffffffffff8p0L, -0x80000000LL, ERRNO_UNCHANGED),
+#endif
+#if LONG_MAX > 0x7fffffff
+    TEST_f_l (lround, 0x7fffff8000000000p0, 0x7fffff8000000000LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#else
+    TEST_f_l (lround, 0x7fffff8000000000p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#ifndef TEST_FLOAT
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lround, 0x7ffffffffffffc00p0, 0x7ffffffffffffc00LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lround, 0x7ffffffffffffc00p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
+#ifdef TEST_LDOUBLE
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lround, 0x7fffffffffffffffp0L, 0x7fffffffffffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lround, 0x7fffffffffffffffp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+    TEST_f_l (lround, 0x7fffffffffffffff.8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# if LDBL_MANT_DIG > 64
+#  if LONG_MAX > 0x7fffffff
+    TEST_f_l (lround, 0x7fffffffffffffff.4p0L, 0x7fffffffffffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#  else
+    TEST_f_l (lround, 0x7fffffffffffffff.4p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#  endif
+    TEST_f_l (lround, 0x7fffffffffffffff.cp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+# if LONG_MAX > 0x7fffffff
+#  if LDBL_MANT_DIG >= 106
+    TEST_f_l (lround, 0x7fffffffffffffff.7fffffffffep0L, 0x7fffffffffffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#  endif
+#  if LDBL_MANT_DIG >= 113
+    TEST_f_l (lround, 0x7fffffffffffffff.7fffffffffffcp0L, 0x7fffffffffffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#  endif
+# else
+#  if LDBL_MANT_DIG >= 106
+    TEST_f_l (lround, 0x7fffffffffffffff.7fffffffffep0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#  endif
+#  if LDBL_MANT_DIG >= 113
+    TEST_f_l (lround, 0x7fffffffffffffff.7fffffffffffcp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#  endif
+# endif
+#endif
+#ifdef TEST_LDOUBLE
+    TEST_f_l (lround, -0x8000000000000001p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lround, -0x8000000000000000.4p0L, LLONG_MIN, ERRNO_UNCHANGED),
+    TEST_f_l (lround, -0x8000000000000000.7fffffffffcp0L, LLONG_MIN, ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lround, -0x8000000000000000.4p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lround, -0x8000000000000000.7fffffffffcp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+    TEST_f_l (lround, -0x8000000000000000.8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_l (lround, -0x8000000000000000.cp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+    TEST_f_l (lround, -0x8000010000000000p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#ifndef TEST_FLOAT
+    TEST_f_l (lround, -0x8000000000000800p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+# if LONG_MAX > 0x7fffffff
+    TEST_f_l (lround, -0x8000000000000000.7fffffffffff8p0L, LLONG_MIN, ERRNO_UNCHANGED),
+# else
+    TEST_f_l (lround, -0x8000000000000000.7fffffffffff8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+#endif
     TEST_f_l (lround, 0, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_l (lround, minus_zero, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_l (lround, min_value, 0.0, ERRNO_UNCHANGED),
@@ -8492,6 +8609,74 @@ static const struct test_f_L_data llround_test_data[] =
     TEST_f_L (llround, -0x1p63, LLONG_MIN, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_L (llround, -0x1p64, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
     TEST_f_L (llround, -0x1p65, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_L (llround, 0x7fffff80p0, 0x7fffff80LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#ifndef TEST_FLOAT
+    TEST_f_L (llround, 0x7fffffffp0, 0x7fffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llround, 0x7fffffff.4p0, 0x7fffffffLL, ERRNO_UNCHANGED),
+    TEST_f_L (llround, 0x7fffffff.7ffffcp0, 0x7fffffffLL, ERRNO_UNCHANGED),
+    TEST_f_L (llround, 0x7fffffff.8p0, 0x80000000LL, ERRNO_UNCHANGED),
+    TEST_f_L (llround, 0x7fffffff.cp0, 0x80000000LL, ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64
+    TEST_f_L (llround, 0x7fffffff.7fffffff8p0L, 0x7fffffffLL, ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_L (llround, 0x7fffffff.7fffffffffffffffffep0L, 0x7fffffffLL, ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_L (llround, 0x7fffffff.7fffffffffffffffffffcp0L, 0x7fffffffLL, ERRNO_UNCHANGED),
+#endif
+#ifndef TEST_FLOAT
+    TEST_f_L (llround, -0x80000000.4p0, -0x80000000LL, ERRNO_UNCHANGED),
+    TEST_f_L (llround, -0x80000000.7ffff8p0, -0x80000000LL, ERRNO_UNCHANGED),
+    TEST_f_L (llround, -0x80000000.8p0, -0x80000001LL, ERRNO_UNCHANGED),
+    TEST_f_L (llround, -0x80000000.cp0, -0x80000001LL, ERRNO_UNCHANGED),
+    TEST_f_L (llround, -0x80000001p0, -0x80000001LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+    TEST_f_L (llround, -0x80000100p0, -0x80000100LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64
+    TEST_f_L (llround, -0x80000000.7fffffffp0L, -0x80000000LL, ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_L (llround, -0x80000000.7fffffffffffffffffcp0L, -0x80000000LL, ERRNO_UNCHANGED),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_L (llround, -0x80000000.7fffffffffffffffffff8p0L, -0x80000000LL, ERRNO_UNCHANGED),
+#endif
+    TEST_f_L (llround, 0x7fffff8000000000p0, 0x7fffff8000000000LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#ifndef TEST_FLOAT
+    TEST_f_L (llround, 0x7ffffffffffffc00p0, 0x7ffffffffffffc00LL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+#endif
+#ifdef TEST_LDOUBLE
+    TEST_f_L (llround, 0x7fffffffffffffffp0L, 0x7fffffffffffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llround, 0x7fffffffffffffff.8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# if LDBL_MANT_DIG > 64
+    TEST_f_L (llround, 0x7fffffffffffffff.4p0L, 0x7fffffffffffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_f_L (llround, 0x7fffffffffffffff.cp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+# endif
+# if LDBL_MANT_DIG >= 106
+    TEST_f_L (llround, 0x7fffffffffffffff.7fffffffffep0L, 0x7fffffffffffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+# if LDBL_MANT_DIG >= 113
+    TEST_f_L (llround, 0x7fffffffffffffff.7fffffffffffcp0L, 0x7fffffffffffffffLL, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+# endif
+#endif
+#ifdef TEST_LDOUBLE
+    TEST_f_L (llround, -0x8000000000000001p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 106
+    TEST_f_L (llround, -0x8000000000000000.4p0L, LLONG_MIN, ERRNO_UNCHANGED),
+    TEST_f_L (llround, -0x8000000000000000.7fffffffffcp0L, LLONG_MIN, ERRNO_UNCHANGED),
+    TEST_f_L (llround, -0x8000000000000000.8p0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+    TEST_f_L (llround, -0x8000000000000000.cp0L, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+    TEST_f_L (llround, -0x8000010000000000p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#ifndef TEST_FLOAT
+    TEST_f_L (llround, -0x8000000000000800p0, IGNORE, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
+#endif
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 113
+    TEST_f_L (llround, -0x8000000000000000.7fffffffffff8p0L, LLONG_MIN, ERRNO_UNCHANGED),
+#endif
     TEST_f_L (llround, 0, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_L (llround, minus_zero, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_L (llround, min_value, 0.0, ERRNO_UNCHANGED),
index bdc838a676bab78263f797ec3a3a8981c7cee7db..91b17b0de96f8cc7fdcafe859449d8d7f937b1a4 100644 (file)
@@ -17,6 +17,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -60,13 +62,33 @@ __lround (double x)
          if (j0 == 20)
            result = (long int) i0;
          else
-           result = ((long int) i0 << (j0 - 20)) | (j >> (52 - j0));
+           {
+             result = ((long int) i0 << (j0 - 20)) | (j >> (52 - j0));
+#ifdef FE_INVALID
+             if (sizeof (long int) == 4
+                 && sign == 1
+                 && result == LONG_MIN)
+               /* Rounding brought the value out of range.  */
+               feraiseexcept (FE_INVALID);
+#endif
+           }
        }
     }
   else
     {
-      /* The number is too large.  It is left implementation defined
-        what happens.  */
+      /* The number is too large.  Unless it rounds to LONG_MIN,
+        FE_INVALID must be raised and the return value is
+        unspecified.  */
+#ifdef FE_INVALID
+      if (sizeof (long int) == 4
+         && x <= (double) LONG_MIN - 0.5)
+       {
+         /* If truncation produces LONG_MIN, the cast will not raise
+            the exception, but may raise "inexact".  */
+         feraiseexcept (FE_INVALID);
+         return LONG_MIN;
+       }
+#endif
       return (long int) x;
     }
 
index 390e733ffd5b07480ceb263fa40ae0152b848e4d..bbc0628c0483e01ed1c99dfb6d2e90286a995cd1 100644 (file)
@@ -16,6 +16,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -48,12 +50,30 @@ __lround (double x)
          i0 += UINT64_C(0x8000000000000) >> j0;
 
          result = i0 >> (52 - j0);
+#ifdef FE_INVALID
+         if (sizeof (long int) == 4
+             && sign == 1
+             && result == LONG_MIN)
+           /* Rounding brought the value out of range.  */
+           feraiseexcept (FE_INVALID);
+#endif
        }
     }
   else
     {
-      /* The number is too large.  It is left implementation defined
-        what happens.  */
+      /* The number is too large.  Unless it rounds to LONG_MIN,
+        FE_INVALID must be raised and the return value is
+        unspecified.  */
+#ifdef FE_INVALID
+      if (sizeof (long int) == 4
+         && x <= (double) LONG_MIN - 0.5)
+       {
+         /* If truncation produces LONG_MIN, the cast will not raise
+            the exception, but may raise "inexact".  */
+         feraiseexcept (FE_INVALID);
+         return LONG_MIN;
+       }
+#endif
       return (long int) x;
     }
 
index 4adc50eaa420b437d7858d160bdb9dba622bde53..235a433dbe999b9ec56f4db4776de22c31a27974 100644 (file)
@@ -18,6 +18,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -60,13 +62,30 @@ __llroundl (long double x)
          if (j0 == 48)
            result = (long long int) i0;
          else
-           result = ((long long int) i0 << (j0 - 48)) | (j >> (112 - j0));
+           {
+             result = ((long long int) i0 << (j0 - 48)) | (j >> (112 - j0));
+#ifdef FE_INVALID
+             if (sign == 1 && result == LLONG_MIN)
+               /* Rounding brought the value out of range.  */
+               feraiseexcept (FE_INVALID);
+#endif
+           }
        }
     }
   else
     {
-      /* The number is too large.  It is left implementation defined
-        what happens.  */
+      /* The number is too large.  Unless it rounds to LLONG_MIN,
+        FE_INVALID must be raised and the return value is
+        unspecified.  */
+#ifdef FE_INVALID
+      if (x <= (long double) LLONG_MIN - 0.5L)
+       {
+         /* If truncation produces LLONG_MIN, the cast will not raise
+            the exception, but may raise "inexact".  */
+         feraiseexcept (FE_INVALID);
+         return LLONG_MIN;
+       }
+#endif
       return (long long int) x;
     }
 
index 64b285e2916feb9109f4983c8cdeeab04cba822b..3c6d26abe1313d1062b18a517702389bd3179674 100644 (file)
@@ -18,6 +18,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -47,6 +49,13 @@ __lroundl (long double x)
            {
              i0 += 0x0000800000000000LL >> j0;
              result = i0 >> (48 - j0);
+#ifdef FE_INVALID
+             if (sizeof (long int) == 4
+                 && sign == 1
+                 && result == LONG_MIN)
+               /* Rounding brought the value out of range.  */
+               feraiseexcept (FE_INVALID);
+#endif
            }
        }
       else if (j0 >= 112)
@@ -60,11 +69,32 @@ __lroundl (long double x)
          if (j0 == 48)
            result = (long int) i0;
          else
-           result = ((long int) i0 << (j0 - 48)) | (j >> (112 - j0));
+           {
+             result = ((long int) i0 << (j0 - 48)) | (j >> (112 - j0));
+#ifdef FE_INVALID
+             if (sizeof (long int) == 8
+                 && sign == 1
+                 && result == LONG_MIN)
+               /* Rounding brought the value out of range.  */
+               feraiseexcept (FE_INVALID);
+#endif
+           }
        }
     }
   else
     {
+      /* The number is too large.  Unless it rounds to LONG_MIN,
+        FE_INVALID must be raised and the return value is
+        unspecified.  */
+#ifdef FE_INVALID
+      if (x <= (long double) LONG_MIN - 0.5L)
+       {
+         /* If truncation produces LONG_MIN, the cast will not raise
+            the exception, but may raise "inexact".  */
+         feraiseexcept (FE_INVALID);
+         return LONG_MIN;
+       }
+#endif
       /* The number is too large.  It is left implementation defined
         what happens.  */
       return (long int) x;
index 8381649269797144df85b99495e60c50066e5a47..17a3ccac084ec43704842d6b58029ba8a47f0a8b 100644 (file)
@@ -17,6 +17,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -64,7 +66,14 @@ __llroundl (long double x)
            ++result;
 
          if (j0 > 31)
-           result = (result << (j0 - 31)) | (j >> (63 - j0));
+           {
+             result = (result << (j0 - 31)) | (j >> (63 - j0));
+#ifdef FE_INVALID
+             if (sign == 1 && result == LLONG_MIN)
+               /* Rounding brought the value out of range.  */
+               feraiseexcept (FE_INVALID);
+#endif
+           }
        }
     }
   else
index 7a59835783708892d2d13847485c87d2268a485f..6bfc2560c39f80b6c0a3b70e41defe3d79f978da 100644 (file)
@@ -17,6 +17,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <fenv.h>
+#include <limits.h>
 #include <math.h>
 
 #include <math_private.h>
@@ -49,6 +51,13 @@ __lroundl (long double x)
            }
 
          result = j >> (31 - j0);
+#ifdef FE_INVALID
+         if (sizeof (long int) == 4
+             && sign == 1
+             && result == LONG_MIN)
+           /* Rounding brought the value out of range.  */
+           feraiseexcept (FE_INVALID);
+#endif
        }
     }
   else if (j0 < (int32_t) (8 * sizeof (long int)) - 1)
@@ -66,13 +75,33 @@ __lroundl (long double x)
          if (j0 == 31)
            result = ures;
          else
-           result = (ures << (j0 - 31)) | (j >> (63 - j0));
+           {
+             result = (ures << (j0 - 31)) | (j >> (63 - j0));
+#ifdef FE_INVALID
+             if (sizeof (long int) == 8
+                 && sign == 1
+                 && result == LONG_MIN)
+               /* Rounding brought the value out of range.  */
+               feraiseexcept (FE_INVALID);
+#endif
+           }
        }
     }
   else
     {
-      /* The number is too large.  It is left implementation defined
-        what happens.  */
+      /* The number is too large.  Unless it rounds to LONG_MIN,
+        FE_INVALID must be raised and the return value is
+        unspecified.  */
+#ifdef FE_INVALID
+      if (sizeof (long int) == 4
+         && x <= (long double) LONG_MIN - 0.5L)
+       {
+         /* If truncation produces LONG_MIN, the cast will not raise
+            the exception, but may raise "inexact".  */
+         feraiseexcept (FE_INVALID);
+         return LONG_MIN;
+       }
+#endif
       return (long int) x;
     }
 
This page took 0.840818 seconds and 5 git commands to generate.