summary refs log tree commit diff
path: root/sysdeps/libm-ieee754/s_llrint.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/libm-ieee754/s_llrint.c')
-rw-r--r--sysdeps/libm-ieee754/s_llrint.c227
1 files changed, 40 insertions, 187 deletions
diff --git a/sysdeps/libm-ieee754/s_llrint.c b/sysdeps/libm-ieee754/s_llrint.c
index faae106ece..a50ba96952 100644
--- a/sysdeps/libm-ieee754/s_llrint.c
+++ b/sysdeps/libm-ieee754/s_llrint.c
@@ -23,9 +23,7 @@
 
 #include "math_private.h"
 
-#ifdef NO_LONG_DOUBLE
-/* The `long double' is in fact the IEEE `double' type.  */
-static long double two52[2] =
+static const long double two52[2] =
 {
   4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
  -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
@@ -33,210 +31,65 @@ static long double two52[2] =
 
 
 long long int
-__llrint (long double x)
+__llrint (double x)
 {
-  int32_t j0,sx;
-  u_int32_t i0, i1, i;
-  long double t, w;
+  int32_t j0;
+  u_int32_t i1, i0;
   long long int result;
+  volatile double w;
+  double t;
+  int sx;
 
   EXTRACT_WORDS (i0, i1, x);
-
-  sx = i0 >> 31;
   j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
+  sx = i0 >> 31;
+  i0 &= 0xfffff;
+  i0 |= 0x100000;
 
   if (j0 < 20)
     {
-      if (j0 < 0)
-	{
-	  if (((i0 & 0x7fffffff) | i1) == 0)
-	    /* The number is 0.  */
-	    result = 0;
-	  else
-	    {
-	      i1 |= i0;
-	      i0 &= 0xfffe0000;
-	      i0 |= ((i1 | -i1) >> 12) & 0x80000;
-	      SET_HIGH_WORD (x, i0);
-	      w = two52[sx] + x;
-	      t = w - two52[sx];
-	      GET_HIGH_WORD (i0, t);
-	      if ((i0 & 0x7fffffff) >= 0x3fff0000)
-		result = sx ? -1 : 1;
-	      else
-		result = 0;
-	    }
-	}
+      if (j0 < -1)
+	return 0;
       else
 	{
-	  u_int32_t i = 0x000fffff >> j0;
-	  if (((i0 & i) | i1) == 0)
-	    {
-	      /* X is not integral.  */
-	      i >>= 1;
-	      if (((i0 & i) | i1) != 0)
-		{
-		  if (j0 == 19)
-		    i1 = 0x40000000;
-		  else
-		    i0 = (i0 & (~i)) | (0x20000 >> j0);
-
-		  INSERT_WORDS (x, i0, i1);
-		  w = two52[sx] + x;
-		  x = w - two52[sx];
-		  EXTRACT_WORDS (i0, i1, x);
-
-		  j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
-		}
-	    }
-
-	  result = ((i0 >> (20 - j0)) & 0xfffff) | (0x00100000 >> (20 - j0));
-	  if (sx)
-	    result = -result;
+	  w = two52[sx] + x;
+	  t = w - two52[sx];
+	  EXTRACT_WORDS (i0, i1, t);
+	  i0 = i & 0xfffff;
+	  i0 |= 0x100000;
+	  j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
+
+	  result = i0 >> (20 - j0);
 	}
     }
-  else if ((unsigned int) j0 < sizeof (long long int) * 8 && j0 < 53)
-    {
-      i = ((u_int32_t) (0xffffffff)) >> (j0 - 20);
-      if ((i1 & i) != 0)
-	{
-	  /* x is not integral.  */
-	  i >>= 1;
-	  if ((i1 & i) != 0)
-	    i1 = (i1 & (~i)) | (0x40000000 >> (j0 - 20));
-	}
-
-      INSERT_WORDS (x, i0, i1);
-      w = two52[sx] + x;
-      x = w - two52[sx];
-      EXTRACT_WORDS (i0, i1, x);
-
-      j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
-
-      result = i0 | 0x00100000;
-      if (j0 > 20)
-	{
-	  result <<= j0 - 20;
-	  result |= i1 >> (52 - j0);
-	}
-      if (sx)
-	result = -result;
-    }
-  else
-    /* Too large.  The number is either +-inf or NaN or it is too
-       large to be effected by rounding.  The standard leaves it
-       undefined what to return when the number is too large to fit in
-       a `long int'.  */
-    result = (long long int) x;
-
-  return result;
-}
-
-#else
-static long double two63[2] =
-{
-  9.223372036854775808000000e+18, /* 0x403E, 0x00000000, 0x00000000 */
- -9.223372036854775808000000e+18  /* 0xC03E, 0x00000000, 0x00000000 */
-};
-
-
-long long int
-__llrint (long double x)
-{
-  int32_t se,j0,sx;
-  u_int32_t i0, i1, i;
-  long long int result;
-  long double w, t;
-
-  GET_LDOUBLE_WORDS (se, i0, i1, x);
-
-  sx = (se >> 15) & 1;
-  j0 = (se & 0x7fff) - 0x3fff;
-
-  if (j0 < 31)
+  else if (j0 < (int32_t) (8 * sizeof (long long int)))
     {
-      if (j0 < 0)
-	{
-	  if (((se & 0x7fff) | i0 | i1) == 0)
-	    /* The number is 0.  */
-	    result = 0;
-	  else
-	    {
-	      i1 |= i0;
-	      i0 &= 0xe0000000;
-	      i0 |= (i1 | -i1) & 0x80000000;
-	      SET_LDOUBLE_MSW (x, i0);
-	      w = two63[sx] + x;
-	      t = w - two63[sx];
-	      GET_LDOUBLE_EXP (i0, t);
-	      if ((i0 & 0x7fff) >= 0x3fff)
-		result = sx ? -1 : 1;
-	      else
-		result = 0;
-	    }
-	}
+      if (j0 >= 52)
+	result = ((long long int) i0 << (j0 - 20)) | (i1 << (j0 - 52));
       else
 	{
-	  u_int32_t i = 0x7fffffff >> j0;
-	  if (((i0 & i) | i1) == 0)
-	    {
-	      /* X is not integral.  */
-	      i >>= 1;
-	      if (((i0 & i) | i1) != 0)
-		{
-		  if (j0 == 31)
-		    i1 = 0x40000000;
-		  else
-		    i0 = (i0 & (~i)) | (0x20000000 >> j0);
-
-		  SET_LDOUBLE_WORDS (x, se, i0, i1);
-		  w = two63[sx] + x;
-		  x = w - two63[sx];
-		  GET_LDOUBLE_WORDS (se, i0, i1, x);
-
-		  sx = (se >> 15) & 1;
-		  j0 = (se & 0x7fff) - 0x3fff;
-		}
-	    }
-
-
-	  result = i0 >> (31 - j0);
+	  w = two52[sx] + x;
+	  t = w - two52[sx];
+	  EXTRACT_WORDS (i0, i1, t);
+	  i0 = i & 0xfffff;
+	  i0 |= 0x100000;
+	  j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
+
+	  result = ((long long int) i0 << (j0 - 20)) | (j >> (52 - j0));
 	}
     }
-  else if ((unsigned int) j0 < sizeof (long long int) * 8 && j0 < 64)
+  else
     {
-      i = ((u_int32_t) (0xffffffff)) >> (j0 - 31);
-      if ((i1 & i) != 0)
-	{
-	  /* x is not integral.  */
-	  i >>= 1;
-	  if ((i1 & i) != 0)
-	    i1 = (i1 & (~i)) | (0x40000000 >> (j0 - 31));
-	}
-
-      SET_LDOUBLE_WORDS (x, se, i0, i1);
-      w = two63[sx] + x;
-      x = w - two63[sx];
-      GET_LDOUBLE_WORDS (se, i0, i1, x);
-
-      j0 = (se & 0x7fff) - 0x3fff;
-
-      result = i0;
-      if (j0 > 31)
-	{
-	  result <<= j0 - 31;
-	  result |= i1 >> (63 - j0);
-	}
+      /* The number is too large.  It is left implementation defined
+	 what happens.  */
+      return (long long int) x;
     }
-  else
-    /* Too large.  The number is either +-inf or NaN or it is too
-       large to be effected by rounding.  The standard leaves it
-       undefined what to return when the number is too large to fit in
-       a `long int'.  */
-    result = (long long int) x;
 
-  return result;
+  return sx ? -result : result;
 }
-#endif
 
 weak_alias (__llrint, llrint)
+#ifdef NO_LONG_DOUBLE
+strong_alias (__llrint, __llrintl)
+weak_alias (__llrint, llrintl)
+#endif