PIPE - Fix a panic introduced by the last commit.
[dragonfly.git] / contrib / gmp / extract-dbl.c
blob9c2ae9b7c08cdbd0328b63cc2a161fbf1fc64652
1 /* __gmp_extract_double -- convert from double to array of mp_limb_t.
3 Copyright 1996, 1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc.
5 This file is part of the GNU MP Library.
7 The GNU MP Library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
12 The GNU MP Library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
20 #include "gmp.h"
21 #include "gmp-impl.h"
23 #ifdef XDEBUG
24 #undef _GMP_IEEE_FLOATS
25 #endif
27 #ifndef _GMP_IEEE_FLOATS
28 #define _GMP_IEEE_FLOATS 0
29 #endif
31 #define BITS_IN_MANTISSA 53
33 /* Extract a non-negative double in d. */
35 int
36 __gmp_extract_double (mp_ptr rp, double d)
38 long exp;
39 unsigned sc;
40 #ifdef _LONG_LONG_LIMB
41 #define BITS_PER_PART 64 /* somewhat bogus */
42 unsigned long long int manl;
43 #else
44 #define BITS_PER_PART GMP_LIMB_BITS
45 unsigned long int manh, manl;
46 #endif
48 /* BUGS
50 1. Should handle Inf and NaN in IEEE specific code.
51 2. Handle Inf and NaN also in default code, to avoid hangs.
52 3. Generalize to handle all GMP_LIMB_BITS >= 32.
53 4. This lits is incomplete and misspelled.
56 ASSERT (d >= 0.0);
58 if (d == 0.0)
60 MPN_ZERO (rp, LIMBS_PER_DOUBLE);
61 return 0;
64 #if _GMP_IEEE_FLOATS
66 #if defined (__alpha) && __GNUC__ == 2 && __GNUC_MINOR__ == 8
67 /* Work around alpha-specific bug in GCC 2.8.x. */
68 volatile
69 #endif
70 union ieee_double_extract x;
71 x.d = d;
72 exp = x.s.exp;
73 #if BITS_PER_PART == 64 /* generalize this to BITS_PER_PART > BITS_IN_MANTISSA */
74 manl = (((mp_limb_t) 1 << 63)
75 | ((mp_limb_t) x.s.manh << 43) | ((mp_limb_t) x.s.manl << 11));
76 if (exp == 0)
78 /* Denormalized number. Don't try to be clever about this,
79 since it is not an important case to make fast. */
80 exp = 1;
83 manl = manl << 1;
84 exp--;
86 while ((manl & GMP_LIMB_HIGHBIT) == 0);
88 #endif
89 #if BITS_PER_PART == 32
90 manh = ((mp_limb_t) 1 << 31) | (x.s.manh << 11) | (x.s.manl >> 21);
91 manl = x.s.manl << 11;
92 if (exp == 0)
94 /* Denormalized number. Don't try to be clever about this,
95 since it is not an important case to make fast. */
96 exp = 1;
99 manh = (manh << 1) | (manl >> 31);
100 manl = manl << 1;
101 exp--;
103 while ((manh & GMP_LIMB_HIGHBIT) == 0);
105 #endif
106 #if BITS_PER_PART != 32 && BITS_PER_PART != 64
107 You need to generalize the code above to handle this.
108 #endif
109 exp -= 1022; /* Remove IEEE bias. */
111 #else
113 /* Unknown (or known to be non-IEEE) double format. */
114 exp = 0;
115 if (d >= 1.0)
117 ASSERT_ALWAYS (d * 0.5 != d);
119 while (d >= 32768.0)
121 d *= (1.0 / 65536.0);
122 exp += 16;
124 while (d >= 1.0)
126 d *= 0.5;
127 exp += 1;
130 else if (d < 0.5)
132 while (d < (1.0 / 65536.0))
134 d *= 65536.0;
135 exp -= 16;
137 while (d < 0.5)
139 d *= 2.0;
140 exp -= 1;
144 d *= (4.0 * ((unsigned long int) 1 << (BITS_PER_PART - 2)));
145 #if BITS_PER_PART == 64
146 manl = d;
147 #endif
148 #if BITS_PER_PART == 32
149 manh = d;
150 manl = (d - manh) * (4.0 * ((unsigned long int) 1 << (BITS_PER_PART - 2)));
151 #endif
153 #endif /* IEEE */
155 sc = (unsigned) (exp + 64 * GMP_NUMB_BITS) % GMP_NUMB_BITS;
157 /* We add something here to get rounding right. */
158 exp = (exp + 64 * GMP_NUMB_BITS) / GMP_NUMB_BITS - 64 * GMP_NUMB_BITS / GMP_NUMB_BITS + 1;
160 #if BITS_PER_PART == 64 && LIMBS_PER_DOUBLE == 2
161 #if GMP_NAIL_BITS == 0
162 if (sc != 0)
164 rp[1] = manl >> (GMP_LIMB_BITS - sc);
165 rp[0] = manl << sc;
167 else
169 rp[1] = manl;
170 rp[0] = 0;
171 exp--;
173 #else
174 if (sc > GMP_NAIL_BITS)
176 rp[1] = manl >> (GMP_LIMB_BITS - sc);
177 rp[0] = (manl << (sc - GMP_NAIL_BITS)) & GMP_NUMB_MASK;
179 else
181 if (sc == 0)
183 rp[1] = manl >> GMP_NAIL_BITS;
184 rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS) & GMP_NUMB_MASK;
185 exp--;
187 else
189 rp[1] = manl >> (GMP_LIMB_BITS - sc);
190 rp[0] = (manl >> (GMP_NAIL_BITS - sc)) & GMP_NUMB_MASK;
193 #endif
194 #endif
196 #if BITS_PER_PART == 64 && LIMBS_PER_DOUBLE == 3
197 if (sc > GMP_NAIL_BITS)
199 rp[2] = manl >> (GMP_LIMB_BITS - sc);
200 rp[1] = (manl << sc - GMP_NAIL_BITS) & GMP_NUMB_MASK;
201 if (sc >= 2 * GMP_NAIL_BITS)
202 rp[0] = 0;
203 else
204 rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS + sc) & GMP_NUMB_MASK;
206 else
208 if (sc == 0)
210 rp[2] = manl >> GMP_NAIL_BITS;
211 rp[1] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS) & GMP_NUMB_MASK;
212 rp[0] = 0;
213 exp--;
215 else
217 rp[2] = manl >> (GMP_LIMB_BITS - sc);
218 rp[1] = (manl >> GMP_NAIL_BITS - sc) & GMP_NUMB_MASK;
219 rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS + sc) & GMP_NUMB_MASK;
222 #endif
224 #if BITS_PER_PART == 32 && LIMBS_PER_DOUBLE == 3
225 #if GMP_NAIL_BITS == 0
226 if (sc != 0)
228 rp[2] = manh >> (GMP_LIMB_BITS - sc);
229 rp[1] = (manh << sc) | (manl >> (GMP_LIMB_BITS - sc));
230 rp[0] = manl << sc;
232 else
234 rp[2] = manh;
235 rp[1] = manl;
236 rp[0] = 0;
237 exp--;
239 #else
240 if (sc > GMP_NAIL_BITS)
242 rp[2] = (manh >> (GMP_LIMB_BITS - sc));
243 rp[1] = ((manh << (sc - GMP_NAIL_BITS)) |
244 (manl >> (GMP_LIMB_BITS - sc + GMP_NAIL_BITS))) & GMP_NUMB_MASK;
245 if (sc >= 2 * GMP_NAIL_BITS)
246 rp[0] = (manl << sc - 2 * GMP_NAIL_BITS) & GMP_NUMB_MASK;
247 else
248 rp[0] = manl >> (2 * GMP_NAIL_BITS - sc) & GMP_NUMB_MASK;
250 else
252 if (sc == 0)
254 rp[2] = manh >> GMP_NAIL_BITS;
255 rp[1] = ((manh << GMP_NUMB_BITS - GMP_NAIL_BITS) | (manl >> 2 * GMP_NAIL_BITS)) & GMP_NUMB_MASK;
256 rp[0] = (manl << GMP_NUMB_BITS - 2 * GMP_NAIL_BITS) & GMP_NUMB_MASK;
257 exp--;
259 else
261 rp[2] = (manh >> (GMP_LIMB_BITS - sc));
262 rp[1] = (manh >> (GMP_NAIL_BITS - sc)) & GMP_NUMB_MASK;
263 rp[0] = ((manh << (GMP_NUMB_BITS - GMP_NAIL_BITS + sc))
264 | (manl >> (GMP_LIMB_BITS - (GMP_NUMB_BITS - GMP_NAIL_BITS + sc)))) & GMP_NUMB_MASK;
267 #endif
268 #endif
270 #if BITS_PER_PART == 32 && LIMBS_PER_DOUBLE > 3
271 if (sc == 0)
273 int i;
275 for (i = LIMBS_PER_DOUBLE - 1; i >= 0; i--)
277 rp[i] = manh >> (BITS_PER_ULONG - GMP_NUMB_BITS);
278 manh = ((manh << GMP_NUMB_BITS)
279 | (manl >> (BITS_PER_ULONG - GMP_NUMB_BITS)));
280 manl = manl << GMP_NUMB_BITS;
282 exp--;
284 else
286 int i;
288 rp[LIMBS_PER_DOUBLE - 1] = (manh >> (GMP_LIMB_BITS - sc));
289 manh = (manh << sc) | (manl >> (GMP_LIMB_BITS - sc));
290 manl = (manl << sc);
291 for (i = LIMBS_PER_DOUBLE - 2; i >= 0; i--)
293 rp[i] = manh >> (BITS_PER_ULONG - GMP_NUMB_BITS);
294 manh = ((manh << GMP_NUMB_BITS)
295 | (manl >> (BITS_PER_ULONG - GMP_NUMB_BITS)));
296 manl = manl << GMP_NUMB_BITS;
299 #endif
301 return exp;