1 /* mpn_get_d -- limbs to double conversion.
2
3 THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY. THEY'RE ALMOST
4 CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
5 FUTURE GNU MP RELEASES.
6
7 Copyright 2003, 2004, 2007, 2009, 2010, 2012, 2018 Free Software
8 Foundation, Inc.
9
10 This file is part of the GNU MP Library.
11
12 The GNU MP Library is free software; you can redistribute it and/or modify
13 it under the terms of either:
14
15 * the GNU Lesser General Public License as published by the Free
16 Software Foundation; either version 3 of the License, or (at your
17 option) any later version.
18
19 or
20
21 * the GNU General Public License as published by the Free Software
22 Foundation; either version 2 of the License, or (at your option) any
23 later version.
24
25 or both in parallel, as here.
26
27 The GNU MP Library is distributed in the hope that it will be useful, but
28 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
29 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
30 for more details.
31
32 You should have received copies of the GNU General Public License and the
33 GNU Lesser General Public License along with the GNU MP Library. If not,
34 see https://www.gnu.org/licenses/. */
35
36 #include "config.h"
37
38 #if HAVE_FLOAT_H
39 #include <float.h> /* for DBL_MANT_DIG and FLT_RADIX */
40 #endif
41
42 #include "gmp-impl.h"
43 #include "longlong.h"
44
45 #ifndef _GMP_IEEE_FLOATS
46 #define _GMP_IEEE_FLOATS 0
47 #endif
48
49 /* To force use of the generic C code for testing, put
50 "#define _GMP_IEEE_FLOATS 0" at this point. */
51
52
53 /* In alpha gcc prior to 3.4, signed DI comparisons involving constants are
54 rearranged from "x < n" to "x+(-n) < 0", which is of course hopelessly
55 wrong if that addition overflows.
56
57 The workaround here avoids this bug by ensuring n is not a literal constant.
58 Note that this is alpha specific. The offending transformation is/was in
59 alpha.c alpha_emit_conditional_branch() under "We want to use cmpcc/bcc".
60
61 Bizarrely, this happens also with Cray cc on alphaev5-cray-unicosmk2.0.6.X,
62 and has the same solution. Don't know why or how. */
63
64 #if HAVE_HOST_CPU_FAMILY_alpha \
65 && ((defined (__GNUC__) && ! __GMP_GNUC_PREREQ(3,4)) \
66 || defined (_CRAY))
67 static volatile const long CONST_1024 = 1024;
68 static volatile const long CONST_NEG_1023 = -1023;
69 static volatile const long CONST_NEG_1022_SUB_53 = -1022 - 53;
70 #else
71 #define CONST_1024 (1024)
72 #define CONST_NEG_1023 (-1023)
73 #define CONST_NEG_1022_SUB_53 (-1022 - 53)
74 #endif
75
76
77 /* Return the value {ptr,size}*2^exp, and negative if sign<0. Must have
78 size>=1, and a non-zero high limb ptr[size-1].
79
80 When we know the fp format, the result is truncated towards zero. This is
81 consistent with other gmp conversions, like mpz_set_f or mpz_set_q, and is
82 easy to implement and test.
83
84 When we do not know the format, such truncation seems much harder. One
85 would need to defeat any rounding mode, including round-up.
86
87 It's felt that GMP is not primarily concerned with hardware floats, and
88 really isn't enhanced by getting involved with hardware rounding modes
89 (which could even be some weird unknown style), so something unambiguous and
90 straightforward is best.
91
92
93 The IEEE code below is the usual case, it knows either a 32-bit or 64-bit
94 limb and is done with shifts and masks. The 64-bit case in particular
95 should come out nice and compact.
96
97 The generic code used to work one bit at a time, which was not only slow,
98 but implicitly relied upon denorms for intermediates, since the lowest bits'
99 weight of a perfectly valid fp number underflows in non-denorm. Therefore,
100 the generic code now works limb-per-limb, initially creating a number x such
101 that 1 <= x <= BASE. (BASE is reached only as result of rounding.) Then
102 x's exponent is scaled with explicit code (not ldexp to avoid libm
103 dependency). It is a tap-dance to avoid underflow or overflow, beware!
104
105
106 Traps:
107
108 Hardware traps for overflow to infinity, underflow to zero, or unsupported
109 denorms may or may not be taken. The IEEE code works bitwise and so
110 probably won't trigger them, the generic code works by float operations and
111 so probably will. This difference might be thought less than ideal, but
112 again its felt straightforward code is better than trying to get intimate
113 with hardware exceptions (of perhaps unknown nature).
114
115
116 Not done:
117
118 mpz_get_d in the past handled size==1 with a cast limb->double. This might
119 still be worthwhile there (for up to the mantissa many bits), but for
120 mpn_get_d here, the cost of applying "exp" to the resulting exponent would
121 probably use up any benefit a cast may have over bit twiddling. Also, if
122 the exponent is pushed into denorm range then bit twiddling is the only
123 option, to ensure the desired truncation is obtained.
124
125
126 Other:
127
128 For reference, note that HPPA 8000, 8200, 8500 and 8600 trap FCNV,UDW,DBL
129 to the kernel for values >= 2^63. This makes it slow, and worse the kernel
130 Linux (what versions?) apparently uses untested code in its trap handling
131 routines, and gets the sign wrong. We don't use such a limb-to-double
132 cast, neither in the IEEE or generic code. */
133
134
135
136 #undef FORMAT_RECOGNIZED
137
138 double
mpn_get_d(mp_srcptr up,mp_size_t size,mp_size_t sign,long exp)139 mpn_get_d (mp_srcptr up, mp_size_t size, mp_size_t sign, long exp)
140 {
141 int lshift, nbits;
142 mp_limb_t x, mhi, mlo;
143
144 ASSERT (size >= 0);
145 ASSERT_MPN (up, size);
146 ASSERT (size == 0 || up[size-1] != 0);
147
148 if (size == 0)
149 return 0.0;
150
151 /* Adjust exp to a radix point just above {up,size}, guarding against
152 overflow. After this exp can of course be reduced to anywhere within
153 the {up,size} region without underflow. */
154 if (UNLIKELY ((unsigned long) (GMP_NUMB_BITS * size)
155 > ((unsigned long) LONG_MAX - exp)))
156 {
157 #if _GMP_IEEE_FLOATS
158 goto ieee_infinity;
159 #endif
160
161 /* generic */
162 exp = LONG_MAX;
163 }
164 else
165 {
166 exp += GMP_NUMB_BITS * size;
167 }
168
169 #if _GMP_IEEE_FLOATS
170 {
171 union ieee_double_extract u;
172
173 up += size;
174
175 #if GMP_LIMB_BITS == 64
176 mlo = up[-1];
177 count_leading_zeros (lshift, mlo);
178
179 exp -= (lshift - GMP_NAIL_BITS) + 1;
180 mlo <<= lshift;
181
182 nbits = GMP_LIMB_BITS - lshift;
183
184 if (nbits < 53 && size > 1)
185 {
186 x = up[-2];
187 x <<= GMP_NAIL_BITS;
188 x >>= nbits;
189 mlo |= x;
190 nbits += GMP_NUMB_BITS;
191
192 if (LIMBS_PER_DOUBLE >= 3 && nbits < 53 && size > 2)
193 {
194 x = up[-3];
195 x <<= GMP_NAIL_BITS;
196 x >>= nbits;
197 mlo |= x;
198 nbits += GMP_NUMB_BITS;
199 }
200 }
201 mhi = mlo >> (32 + 11);
202 mlo = mlo >> 11; /* later implicitly truncated to 32 bits */
203 #endif
204 #if GMP_LIMB_BITS == 32
205 x = *--up;
206 count_leading_zeros (lshift, x);
207
208 exp -= (lshift - GMP_NAIL_BITS) + 1;
209 x <<= lshift;
210 mhi = x >> 11;
211
212 if (lshift < 11) /* FIXME: never true if NUMB < 20 bits */
213 {
214 /* All 20 bits in mhi */
215 mlo = x << 21;
216 /* >= 1 bit in mlo */
217 nbits = GMP_LIMB_BITS - lshift - 21;
218 }
219 else
220 {
221 if (size > 1)
222 {
223 nbits = GMP_LIMB_BITS - lshift;
224
225 x = *--up, size--;
226 x <<= GMP_NAIL_BITS;
227 mhi |= x >> nbits >> 11;
228
229 mlo = x << (GMP_LIMB_BITS - nbits - 11);
230 nbits = nbits + 11 - GMP_NAIL_BITS;
231 }
232 else
233 {
234 mlo = 0;
235 goto done;
236 }
237 }
238
239 /* Now all needed bits in mhi have been accumulated. Add bits to mlo. */
240
241 if (LIMBS_PER_DOUBLE >= 2 && nbits < 32 && size > 1)
242 {
243 x = up[-1];
244 x <<= GMP_NAIL_BITS;
245 x >>= nbits;
246 mlo |= x;
247 nbits += GMP_NUMB_BITS;
248
249 if (LIMBS_PER_DOUBLE >= 3 && nbits < 32 && size > 2)
250 {
251 x = up[-2];
252 x <<= GMP_NAIL_BITS;
253 x >>= nbits;
254 mlo |= x;
255 nbits += GMP_NUMB_BITS;
256
257 if (LIMBS_PER_DOUBLE >= 4 && nbits < 32 && size > 3)
258 {
259 x = up[-3];
260 x <<= GMP_NAIL_BITS;
261 x >>= nbits;
262 mlo |= x;
263 nbits += GMP_NUMB_BITS;
264 }
265 }
266 }
267
268 done:;
269
270 #endif
271 if (UNLIKELY (exp >= CONST_1024))
272 {
273 /* overflow, return infinity */
274 ieee_infinity:
275 mhi = 0;
276 mlo = 0;
277 exp = 1024;
278 }
279 else if (UNLIKELY (exp <= CONST_NEG_1023))
280 {
281 int rshift;
282
283 if (LIKELY (exp <= CONST_NEG_1022_SUB_53))
284 return 0.0; /* denorm underflows to zero */
285
286 rshift = -1022 - exp;
287 ASSERT (rshift > 0 && rshift < 53);
288 #if GMP_LIMB_BITS > 53
289 mlo >>= rshift;
290 mhi = mlo >> 32;
291 #else
292 if (rshift >= 32)
293 {
294 mlo = mhi;
295 mhi = 0;
296 rshift -= 32;
297 }
298 lshift = GMP_LIMB_BITS - rshift;
299 mlo = (mlo >> rshift) | (rshift == 0 ? 0 : mhi << lshift);
300 mhi >>= rshift;
301 #endif
302 exp = -1023;
303 }
304 u.s.manh = mhi;
305 u.s.manl = mlo;
306 u.s.exp = exp + 1023;
307 u.s.sig = (sign < 0);
308 return u.d;
309 }
310 #define FORMAT_RECOGNIZED 1
311 #endif
312
313 #if HAVE_DOUBLE_VAX_D
314 {
315 union double_extract u;
316
317 up += size;
318
319 mhi = up[-1];
320
321 count_leading_zeros (lshift, mhi);
322 exp -= lshift;
323 mhi <<= lshift;
324
325 mlo = 0;
326 if (size > 1)
327 {
328 mlo = up[-2];
329 if (lshift != 0)
330 mhi += mlo >> (GMP_LIMB_BITS - lshift);
331 mlo <<= lshift;
332
333 if (size > 2 && lshift > 8)
334 {
335 x = up[-3];
336 mlo += x >> (GMP_LIMB_BITS - lshift);
337 }
338 }
339
340 if (UNLIKELY (exp >= 128))
341 {
342 /* overflow, return maximum number */
343 mhi = 0xffffffff;
344 mlo = 0xffffffff;
345 exp = 127;
346 }
347 else if (UNLIKELY (exp < -128))
348 {
349 return 0.0; /* underflows to zero */
350 }
351
352 u.s.man3 = mhi >> 24; /* drop msb, since implicit */
353 u.s.man2 = mhi >> 8;
354 u.s.man1 = (mhi << 8) + (mlo >> 24);
355 u.s.man0 = mlo >> 8;
356 u.s.exp = exp + 128;
357 u.s.sig = sign < 0;
358 return u.d;
359 }
360 #define FORMAT_RECOGNIZED 1
361 #endif
362
363 #if ! FORMAT_RECOGNIZED
364
365 #if !defined(GMP_DBL_MANT_BITS)
366 #if defined(DBL_MANT_DIG) && FLT_RADIX == 2
367 #define GMP_DBL_MANT_BITS DBL_MANT_DIG
368 #else
369 /* FIXME: Chose a smarter default value. */
370 #define GMP_DBL_MANT_BITS (16 * sizeof (double))
371 #endif
372 #endif
373
374 { /* Non-IEEE or strange limb size, generically convert
375 GMP_DBL_MANT_BITS bits. */
376 mp_limb_t l;
377 int m;
378 mp_size_t i;
379 double d, weight;
380 unsigned long uexp;
381
382 /* First generate an fp number disregarding exp, instead keeping things
383 within the numb base factor from 1, which should prevent overflow and
384 underflow even for the most exponent limited fp formats. */
385 i = size - 1;
386 l = up[i];
387 count_leading_zeros (m, l);
388 m = m + GMP_DBL_MANT_BITS - GMP_LIMB_BITS;
389 if (m < 0)
390 l &= GMP_NUMB_MAX << -m;
391 d = l;
392 for (weight = 1/MP_BASE_AS_DOUBLE; m > 0 && --i >= 0;)
393 {
394 l = up[i];
395 m -= GMP_NUMB_BITS;
396 if (m < 0)
397 l &= GMP_NUMB_MAX << -m;
398 d += l * weight;
399 weight /= MP_BASE_AS_DOUBLE;
400 if (weight == 0)
401 break;
402 }
403
404 /* Now apply exp. */
405 exp -= GMP_NUMB_BITS;
406 if (exp > 0)
407 {
408 weight = 2.0;
409 uexp = exp;
410 }
411 else
412 {
413 weight = 0.5;
414 uexp = NEG_CAST (unsigned long, exp);
415 }
416 #if 1
417 /* Square-and-multiply exponentiation. */
418 if (uexp & 1)
419 d *= weight;
420 while (uexp >>= 1)
421 {
422 weight *= weight;
423 if (uexp & 1)
424 d *= weight;
425 }
426 #else
427 /* Plain exponentiation. */
428 while (uexp > 0)
429 {
430 d *= weight;
431 uexp--;
432 }
433 #endif
434
435 return sign >= 0 ? d : -d;
436 }
437 #endif
438 }
439