Update.
[glibc.git] / sysdeps / libm-ieee754 / s_rinttoll.c
blobb2fccd17b76ba9d85dc7181dfb051f6db0cf3cae
1 /* Round argument to nearest integral value according to current rounding
2 direction.
3 Copyright (C) 1997 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with the GNU C Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 #include <math.h>
24 #include "math_private.h"
26 #ifdef NO_LONG_DOUBLE
27 /* The `long double' is in fact the IEEE `double' type. */
28 static long double two52[2] =
30 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
31 -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
35 long long int
36 __rinttoll (long double x)
38 int32_t j0,sx;
39 u_int32_t i0, i1, i;
40 long double t, w;
41 long long int result;
43 EXTRACT_WORDS (i0, i1, x);
45 sx = i0 >> 31;
46 j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
48 if (j0 < 20)
50 if (j0 < 0)
52 if (((i0 & 0x7fffffff) | i1) == 0)
53 /* The number is 0. */
54 result = 0;
55 else
57 i1 |= i0;
58 i0 &= 0xfffe0000;
59 i0 |= ((i1 | -i1) >> 12) & 0x80000;
60 SET_HIGH_WORD (x, i0);
61 w = two52[sx] + x;
62 t = w - two52[sx];
63 GET_HIGH_WORD (i0, t);
64 if ((i0 & 0x7fffffff) >= 0x3fff0000)
65 result = sx ? -1 : 1;
66 else
67 result = 0;
70 else
72 u_int32_t i = 0x000fffff >> j0;
73 if (((i0 & i) | i1) == 0)
75 /* X is not integral. */
76 i >>= 1;
77 if (((i0 & i) | i1) != 0)
79 if (j0 == 19)
80 i1 = 0x40000000;
81 else
82 i0 = (i0 & (~i)) | (0x20000 >> j0);
84 INSERT_WORDS (x, i0, i1);
85 w = two52[sx] + x;
86 x = w - two52[sx];
87 EXTRACT_WORDS (i0, i1, x);
89 j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
93 result = ((i0 >> (20 - j0)) & 0xfffff) | (0x00100000 >> (20 - j0));
94 if (sx)
95 result = -result;
98 else if ((unsigned int) j0 < sizeof (long long int) * 8 && j0 < 53)
100 i = ((u_int32_t) (0xffffffff)) >> (j0 - 20);
101 if ((i1 & i) != 0)
103 /* x is not integral. */
104 i >>= 1;
105 if ((i1 & i) != 0)
106 i1 = (i1 & (~i)) | (0x40000000 >> (j0 - 20));
109 INSERT_WORDS (x, i0, i1);
110 w = two52[sx] + x;
111 x = w - two52[sx];
112 EXTRACT_WORDS (i0, i1, x);
114 j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
116 result = i0 | 0x00100000;
117 if (j0 > 20)
119 result <<= j0 - 20;
120 result |= i1 >> (52 - j0);
122 if (sx)
123 result = -result;
125 else
126 /* Too large. The number is either +-inf or NaN or it is too
127 large to be effected by rounding. The standard leaves it
128 undefined what to return when the number is too large to fit in
129 a `long int'. */
130 result = (long long int) x;
132 return result;
135 #else
136 static long double two63[2] =
138 9.223372036854775808000000e+18, /* 0x403E, 0x00000000, 0x00000000 */
139 -9.223372036854775808000000e+18 /* 0xC03E, 0x00000000, 0x00000000 */
143 long long int
144 __rinttoll (long double x)
146 int32_t se,j0,sx;
147 u_int32_t i0, i1, i;
148 long long int result;
149 long double w, t;
151 GET_LDOUBLE_WORDS (se, i0, i1, x);
153 sx = (se >> 15) & 1;
154 j0 = (se & 0x7fff) - 0x3fff;
156 if (j0 < 31)
158 if (j0 < 0)
160 if (((se & 0x7fff) | i0 | i1) == 0)
161 /* The number is 0. */
162 result = 0;
163 else
165 i1 |= i0;
166 i0 &= 0xe0000000;
167 i0 |= (i1 | -i1) & 0x80000000;
168 SET_LDOUBLE_MSW (x, i0);
169 w = two63[sx] + x;
170 t = w - two63[sx];
171 GET_LDOUBLE_EXP (i0, t);
172 if ((i0 & 0x7fff) >= 0x3fff)
173 result = sx ? -1 : 1;
174 else
175 result = 0;
178 else
180 u_int32_t i = 0x7fffffff >> j0;
181 if (((i0 & i) | i1) == 0)
183 /* X is not integral. */
184 i >>= 1;
185 if (((i0 & i) | i1) != 0)
187 if (j0 == 31)
188 i1 = 0x40000000;
189 else
190 i0 = (i0 & (~i)) | (0x20000000 >> j0);
192 SET_LDOUBLE_WORDS (x, se, i0, i1);
193 w = two63[sx] + x;
194 x = w - two63[sx];
195 GET_LDOUBLE_WORDS (se, i0, i1, x);
197 sx = (se >> 15) & 1;
198 j0 = (se & 0x7fff) - 0x3fff;
203 result = i0 >> (31 - j0);
206 else if ((unsigned int) j0 < sizeof (long long int) * 8 && j0 < 64)
208 i = ((u_int32_t) (0xffffffff)) >> (j0 - 31);
209 if ((i1 & i) != 0)
211 /* x is not integral. */
212 i >>= 1;
213 if ((i1 & i) != 0)
214 i1 = (i1 & (~i)) | (0x40000000 >> (j0 - 31));
217 SET_LDOUBLE_WORDS (x, se, i0, i1);
218 w = two63[sx] + x;
219 x = w - two63[sx];
220 GET_LDOUBLE_WORDS (se, i0, i1, x);
222 j0 = (se & 0x7fff) - 0x3fff;
224 result = i0;
225 if (j0 > 31)
227 result <<= j0 - 31;
228 result |= i1 >> (63 - j0);
231 else
232 /* Too large. The number is either +-inf or NaN or it is too
233 large to be effected by rounding. The standard leaves it
234 undefined what to return when the number is too large to fit in
235 a `long int'. */
236 result = (long long int) x;
238 return result;
240 #endif
242 weak_alias (__rinttoll, rinttoll)