summaryrefslogtreecommitdiff
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