]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sysdeps/ieee754/dbl-64/s_lrint.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / ieee754 / dbl-64 / s_lrint.c
index d1561bfd2560c3074c95070e36cbdf5e368094c4..4e7cbef97b7e26a636221fcc36d28d38371343d7 100644 (file)
@@ -1,6 +1,6 @@
 /* Round argument to nearest integral value according to current rounding
    direction.
-   Copyright (C) 1997, 2004, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-2016 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
    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>
+#include <fix-fp-int-convert-overflow.h>
 
 static const double two52[2] =
 {
@@ -33,8 +36,8 @@ long int
 __lrint (double x)
 {
   int32_t j0;
-  u_int32_t i0,i1;
-  volatile double w;
+  u_int32_t i0, i1;
+  double w;
   double t;
   long int result;
   int sx;
@@ -47,7 +50,7 @@ __lrint (double x)
 
   if (j0 < 20)
     {
-      w = two52[sx] + x;
+      w = math_narrow_eval (two52[sx] + x);
       t = w - two52[sx];
       EXTRACT_WORDS (i0, i1, t);
       j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
@@ -59,11 +62,25 @@ __lrint (double x)
   else if (j0 < (int32_t) (8 * sizeof (long int)) - 1)
     {
       if (j0 >= 52)
-       result = ((long int) i0 << (j0 - 20)) | (i1 << (j0 - 52));
+       result = ((long int) i0 << (j0 - 20)) | ((long int) i1 << (j0 - 52));
       else
        {
-         w = two52[sx] + x;
-         t = w - two52[sx];
+#if defined FE_INVALID || defined FE_INEXACT
+         /* X < LONG_MAX + 1 implied by J0 < 31.  */
+         if (sizeof (long int) == 4
+             && x > (double) LONG_MAX)
+           {
+             /* In the event of overflow we must raise the "invalid"
+                exception, but not "inexact".  */
+             t = __nearbyint (x);
+             feraiseexcept (t == LONG_MAX ? FE_INEXACT : FE_INVALID);
+           }
+         else
+#endif
+           {
+             w = math_narrow_eval (two52[sx] + x);
+             t = w - two52[sx];
+           }
          EXTRACT_WORDS (i0, i1, t);
          j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
          i0 &= 0xfffff;
@@ -77,8 +94,26 @@ __lrint (double x)
     }
   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.  */
+#if defined FE_INVALID || defined FE_INEXACT
+      if (sizeof (long int) == 4
+         && x < (double) LONG_MIN
+         && x > (double) LONG_MIN - 1.0)
+       {
+         /* If truncation produces LONG_MIN, the cast will not raise
+            the exception, but may raise "inexact".  */
+         t = __nearbyint (x);
+         feraiseexcept (t == LONG_MIN ? FE_INEXACT : FE_INVALID);
+         return LONG_MIN;
+       }
+      else if (FIX_DBL_LONG_CONVERT_OVERFLOW && x != (double) LONG_MIN)
+       {
+         feraiseexcept (FE_INVALID);
+         return sx == 0 ? LONG_MAX : LONG_MIN;
+       }
+#endif
       return (long int) x;
     }