xref: /dragonfly/contrib/gmp/mpn/generic/get_d.c (revision cfd1aba3)
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 Free Software Foundation, Inc.
8 
9 This file is part of the GNU MP Library.
10 
11 The GNU MP Library is free software; you can redistribute it and/or modify
12 it under the terms of the GNU Lesser General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or (at your
14 option) any later version.
15 
16 The GNU MP Library is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
19 License for more details.
20 
21 You should have received a copy of the GNU Lesser General Public License
22 along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
23 
24 #include "gmp.h"
25 #include "gmp-impl.h"
26 #include "longlong.h"
27 
28 #ifndef _GMP_IEEE_FLOATS
29 #define _GMP_IEEE_FLOATS 0
30 #endif
31 
32 #if ! _GMP_IEEE_FLOATS
33 /* dummy definition, just to let dead code compile */
34 union ieee_double_extract {
35   struct {
36     int manh, manl, sig, exp;
37   } s;
38   double d;
39 };
40 #endif
41 
42 /* To force use of the generic C code for testing, put
43    "#define _GMP_IEEE_FLOATS 0" at this point.  */
44 
45 
46 
47 /* In alpha gcc prior to 3.4, signed DI comparisons involving constants are
48    rearranged from "x < n" to "x+(-n) < 0", which is of course hopelessly
49    wrong if that addition overflows.
50 
51    The workaround here avoids this bug by ensuring n is not a literal
52    constant.  Note that this is alpha specific.  The offending transformation
53    is/was in alpha.c alpha_emit_conditional_branch() under "We want to use
54    cmpcc/bcc".
55 
56    Bizarrely, it turns out this happens also with Cray cc on
57    alphaev5-cray-unicosmk2.0.6.X, and has the same solution.  Don't know why
58    or how.  */
59 
60 #if HAVE_HOST_CPU_FAMILY_alpha				\
61   && ((defined (__GNUC__) && ! __GMP_GNUC_PREREQ(3,4))	\
62       || defined (_CRAY))
63 static volatile const long CONST_1024 = 1024;
64 static volatile const long CONST_NEG_1023 = -1023;
65 static volatile const long CONST_NEG_1022_SUB_53 = -1022 - 53;
66 #else
67 #define CONST_1024	      (1024)
68 #define CONST_NEG_1023	      (-1023)
69 #define CONST_NEG_1022_SUB_53 (-1022 - 53)
70 #endif
71 
72 
73 
74 /* Return the value {ptr,size}*2^exp, and negative if sign<0.
75    Must have size>=1, and a non-zero high limb ptr[size-1].
76 
77    {ptr,size} is truncated towards zero.  This is consistent with other gmp
78    conversions, like mpz_set_f or mpz_set_q, and is easy to implement and
79    test.
80 
81    In the past conversions had attempted (imperfectly) to let the hardware
82    float rounding mode take effect, but that gets tricky since multiple
83    roundings need to be avoided, or taken into account, and denorms mean the
84    effective precision of the mantissa is not constant.  (For reference,
85    mpz_get_d on IEEE systems was ok, except it operated on the absolute
86    value.  mpf_get_d and mpq_get_d suffered from multiple roundings and from
87    not always using enough bits to get the rounding right.)
88 
89    It's felt that GMP is not primarily concerned with hardware floats, and
90    really isn't enhanced by getting involved with hardware rounding modes
91    (which could even be some weird unknown style), so something unambiguous
92    and straightforward is best.
93 
94 
95    The IEEE code below is the usual case, it knows either a 32-bit or 64-bit
96    limb and is done with shifts and masks.  The 64-bit case in particular
97    should come out nice and compact.
98 
99    The generic code works one bit at a time, which will be quite slow, but
100    should support any binary-based "double" and be safe against any rounding
101    mode.  Note in particular it works on IEEE systems too.
102 
103 
104    Traps:
105 
106    Hardware traps for overflow to infinity, underflow to zero, or
107    unsupported denorms may or may not be taken.  The IEEE code works bitwise
108    and so probably won't trigger them, the generic code works by float
109    operations and so probably will.  This difference might be thought less
110    than ideal, but again its felt straightforward code is better than trying
111    to get intimate with hardware exceptions (of perhaps unknown nature).
112 
113 
114    Not done:
115 
116    mpz_get_d in the past handled size==1 with a cast limb->double.  This
117    might still be worthwhile there (for up to the mantissa many bits), but
118    for mpn_get_d here, the cost of applying "exp" to the resulting exponent
119    would probably use up any benefit a cast may have over bit twiddling.
120    Also, if the exponent is pushed into denorm range then bit twiddling is
121    the only option, to ensure the desired truncation is obtained.
122 
123 
124    Other:
125 
126    For reference, note that HPPA 8000, 8200, 8500 and 8600 trap FCNV,UDW,DBL
127    to the kernel for values >= 2^63.  This makes it slow, and worse the kernel
128    Linux (what versions?) apparently uses untested code in its trap handling
129    routines, and gets the sign wrong.  We don't use such a limb-to-double
130    cast, neither in the IEEE or generic code.  */
131 
132 
133 double
134 mpn_get_d (mp_srcptr up, mp_size_t size, mp_size_t sign, long exp)
135 {
136   ASSERT (size >= 0);
137   ASSERT_MPN (up, size);
138   ASSERT (size == 0 || up[size-1] != 0);
139 
140   if (size == 0)
141     return 0.0;
142 
143   /* Adjust exp to a radix point just above {up,size}, guarding against
144      overflow.  After this exp can of course be reduced to anywhere within
145      the {up,size} region without underflow.  */
146   if (UNLIKELY ((unsigned long) (GMP_NUMB_BITS * size)
147 		> (unsigned long) (LONG_MAX - exp)))
148     {
149       if (_GMP_IEEE_FLOATS)
150 	goto ieee_infinity;
151 
152       /* generic */
153       exp = LONG_MAX;
154     }
155   else
156     {
157       exp += GMP_NUMB_BITS * size;
158     }
159 
160 
161 #if 1
162 {
163   int lshift, nbits;
164   union ieee_double_extract u;
165   mp_limb_t x, mhi, mlo;
166 #if GMP_LIMB_BITS == 64
167   mp_limb_t m;
168   up += size;
169   m = *--up;
170   count_leading_zeros (lshift, m);
171 
172   exp -= (lshift - GMP_NAIL_BITS) + 1;
173   m <<= lshift;
174 
175   nbits = GMP_LIMB_BITS - lshift;
176 
177   if (nbits < 53 && size > 1)
178     {
179       x = *--up;
180       x <<= GMP_NAIL_BITS;
181       x >>= nbits;
182       m |= x;
183       nbits += GMP_NUMB_BITS;
184 
185       if (LIMBS_PER_DOUBLE >= 3 && nbits < 53 && size > 2)
186 	{
187 	  x = *--up;
188 	  x <<= GMP_NAIL_BITS;
189 	  x >>= nbits;
190 	  m |= x;
191 	  nbits += GMP_NUMB_BITS;
192 	}
193     }
194   mhi = m >> (32 + 11);
195   mlo = m >> 11;
196 #endif
197 #if GMP_LIMB_BITS == 32
198   up += size;
199   x = *--up, size--;
200   count_leading_zeros (lshift, x);
201 
202   exp -= (lshift - GMP_NAIL_BITS) + 1;
203   x <<= lshift;
204   mhi = x >> 11;
205 
206   if (lshift < 11)		/* FIXME: never true if NUMB < 20 bits */
207     {
208       /* All 20 bits in mhi */
209       mlo = x << 21;
210       /* >= 1 bit in mlo */
211       nbits = GMP_LIMB_BITS - lshift - 21;
212     }
213   else
214     {
215       if (size != 0)
216 	{
217 	  nbits = GMP_LIMB_BITS - lshift;
218 
219 	  x = *--up, size--;
220 	  x <<= GMP_NAIL_BITS;
221 	  mhi |= x >> nbits >> 11;
222 
223 	  mlo = x << GMP_LIMB_BITS - nbits - 11;
224 	  nbits = nbits + 11 - GMP_NAIL_BITS;
225 	}
226       else
227 	{
228 	  mlo = 0;
229 	  goto done;
230 	}
231     }
232 
233   if (LIMBS_PER_DOUBLE >= 2 && nbits < 32 && size != 0)
234     {
235       x = *--up, size--;
236       x <<= GMP_NAIL_BITS;
237       x >>= nbits;
238       mlo |= x;
239       nbits += GMP_NUMB_BITS;
240 
241       if (LIMBS_PER_DOUBLE >= 3 && nbits < 32 && size != 0)
242 	{
243 	  x = *--up, size--;
244 	  x <<= GMP_NAIL_BITS;
245 	  x >>= nbits;
246 	  mlo |= x;
247 	  nbits += GMP_NUMB_BITS;
248 
249 	  if (LIMBS_PER_DOUBLE >= 4 && nbits < 32 && size != 0)
250 	    {
251 	      x = *--up;
252 	      x <<= GMP_NAIL_BITS;
253 	      x >>= nbits;
254 	      mlo |= x;
255 	      nbits += GMP_NUMB_BITS;
256 	    }
257 	}
258     }
259 
260  done:;
261 
262 #endif
263   {
264     if (UNLIKELY (exp >= CONST_1024))
265       {
266 	/* overflow, return infinity */
267       ieee_infinity:
268 	mhi = 0;
269 	mlo = 0;
270 	exp = 1024;
271       }
272     else if (UNLIKELY (exp <= CONST_NEG_1023))
273       {
274 	int rshift;
275 
276 	if (LIKELY (exp <= CONST_NEG_1022_SUB_53))
277 	  return 0.0;	 /* denorm underflows to zero */
278 
279 	rshift = -1022 - exp;
280 	ASSERT (rshift > 0 && rshift < 53);
281 #if GMP_LIMB_BITS > 53
282 	mlo >>= rshift;
283 	mhi = mlo >> 32;
284 #else
285 	if (rshift >= 32)
286 	  {
287 	    mlo = mhi;
288 	    mhi = 0;
289 	    rshift -= 32;
290 	  }
291 	lshift = GMP_LIMB_BITS - rshift;
292 	mlo = (mlo >> rshift) | (rshift == 0 ? 0 : mhi << lshift);
293 	mhi >>= rshift;
294 #endif
295 	exp = -1023;
296       }
297   }
298   u.s.manh = mhi;
299   u.s.manl = mlo;
300   u.s.exp = exp + 1023;
301   u.s.sig = (sign < 0);
302   return u.d;
303 }
304 #else
305 
306 
307 #define ONE_LIMB    (GMP_LIMB_BITS == 64 && 2*GMP_NUMB_BITS >= 53)
308 #define TWO_LIMBS   (GMP_LIMB_BITS == 32 && 3*GMP_NUMB_BITS >= 53)
309 
310   if (_GMP_IEEE_FLOATS && (ONE_LIMB || TWO_LIMBS))
311     {
312       union ieee_double_extract	 u;
313       mp_limb_t	 m0, m1, m2, rmask;
314       int	 lshift, rshift;
315 
316       m0 = up[size-1];			    /* high limb */
317       m1 = (size >= 2 ? up[size-2] : 0);   /* second highest limb */
318       count_leading_zeros (lshift, m0);
319 
320       /* relative to just under high non-zero bit */
321       exp -= (lshift - GMP_NAIL_BITS) + 1;
322 
323       if (ONE_LIMB)
324 	{
325 	  /* lshift to have high of m0 non-zero, and collapse nails */
326 	  rshift = GMP_LIMB_BITS - lshift;
327 	  m1 <<= GMP_NAIL_BITS;
328 	  rmask = GMP_NAIL_BITS == 0 && lshift == 0 ? 0 : MP_LIMB_T_MAX;
329 	  m0 = (m0 << lshift) | ((m1 >> rshift) & rmask);
330 
331 	  /* rshift back to have bit 53 of m0 the high non-zero */
332 	  m0 >>= 11;
333 	}
334       else /* TWO_LIMBS */
335 	{
336 	  m2 = (size >= 3 ? up[size-3] : 0);  /* third highest limb */
337 
338 	  /* collapse nails from m1 and m2 */
339 #if GMP_NAIL_BITS != 0
340 	  m1 = (m1 << GMP_NAIL_BITS) | (m2 >> (GMP_NUMB_BITS-GMP_NAIL_BITS));
341 	  m2 <<= 2*GMP_NAIL_BITS;
342 #endif
343 
344 	  /* lshift to have high of m0:m1 non-zero, collapse nails from m0 */
345 	  rshift = GMP_LIMB_BITS - lshift;
346 	  rmask = (GMP_NAIL_BITS == 0 && lshift == 0 ? 0 : MP_LIMB_T_MAX);
347 	  m0 = (m0 << lshift) | ((m1 >> rshift) & rmask);
348 	  m1 = (m1 << lshift) | ((m2 >> rshift) & rmask);
349 
350 	  /* rshift back to have bit 53 of m0:m1 the high non-zero */
351 	  m1 = (m1 >> 11) | (m0 << (GMP_LIMB_BITS-11));
352 	  m0 >>= 11;
353 	}
354 
355       if (UNLIKELY (exp >= CONST_1024))
356 	{
357 	  /* overflow, return infinity */
358 	ieee_infinity:
359 	  m0 = 0;
360 	  m1 = 0;
361 	  exp = 1024;
362 	}
363       else if (UNLIKELY (exp <= CONST_NEG_1023))
364 	{
365 	  if (LIKELY (exp <= CONST_NEG_1022_SUB_53))
366 	    return 0.0;	 /* denorm underflows to zero */
367 
368 	  rshift = -1022 - exp;
369 	  ASSERT (rshift > 0 && rshift < 53);
370 	  if (ONE_LIMB)
371 	    {
372 	      m0 >>= rshift;
373 	    }
374 	  else /* TWO_LIMBS */
375 	    {
376 	      if (rshift >= 32)
377 		{
378 		  m1 = m0;
379 		  m0 = 0;
380 		  rshift -= 32;
381 		}
382 	      lshift = GMP_LIMB_BITS - rshift;
383 	      m1 = (m1 >> rshift) | (rshift == 0 ? 0 : m0 << lshift);
384 	      m0 >>= rshift;
385 	    }
386 	  exp = -1023;
387 	}
388 
389       if (ONE_LIMB)
390 	{
391 #if GMP_LIMB_BITS > 32	/* avoid compiler warning about big shift */
392 	  u.s.manh = m0 >> 32;
393 #endif
394 	  u.s.manl = m0;
395 	}
396       else /* TWO_LIMBS */
397 	{
398 	  u.s.manh = m0;
399 	  u.s.manl = m1;
400 	}
401 
402       u.s.exp = exp + 1023;
403       u.s.sig = (sign < 0);
404       return u.d;
405     }
406   else
407     {
408       /* Non-IEEE or strange limb size, do something generic. */
409 
410       mp_size_t	     i;
411       mp_limb_t	     limb, bit;
412       int	     shift;
413       double	     base, factor, prev_factor, d, new_d, diff;
414 
415       /* "limb" is "up[i]" the limb being examined, "bit" is a mask for the
416 	 bit being examined, initially the highest non-zero bit.  */
417       i = size-1;
418       limb = up[i];
419       count_leading_zeros (shift, limb);
420       bit = GMP_LIMB_HIGHBIT >> shift;
421 
422       /* relative to just under high non-zero bit */
423       exp -= (shift - GMP_NAIL_BITS) + 1;
424 
425       /* Power up "factor" to 2^exp, being the value of the "bit" in "limb"
426 	 being examined.  */
427       base = (exp >= 0 ? 2.0 : 0.5);
428       exp = ABS (exp);
429       factor = 1.0;
430       for (;;)
431 	{
432 	  if (exp & 1)
433 	    {
434 	      prev_factor = factor;
435 	      factor *= base;
436 	      FORCE_DOUBLE (factor);
437 	      if (factor == 0.0)
438 		return 0.0;	/* underflow */
439 	      if (factor == prev_factor)
440 		{
441 		  d = factor;	  /* overflow, apparent infinity */
442 		  goto generic_done;
443 		}
444 	    }
445 	  exp >>= 1;
446 	  if (exp == 0)
447 	    break;
448 	  base *= base;
449 	}
450 
451       /* Add a "factor" for each non-zero bit, working from high to low.
452 	 Stop if any rounding occurs, hence implementing a truncation.
453 
454 	 Note no attention is paid to DBL_MANT_DIG, since the effective
455 	 number of bits in the mantissa isn't constant when in denorm range.
456 	 We also encountered an ARM system with apparently somewhat doubtful
457 	 software floats where DBL_MANT_DIG claimed 53 bits but only 32
458 	 actually worked.  */
459 
460       d = factor;  /* high bit */
461       for (;;)
462 	{
463 	  factor *= 0.5;  /* next bit */
464 	  bit >>= 1;
465 	  if (bit == 0)
466 	    {
467 	      /* next limb, if any */
468 	      i--;
469 	      if (i < 0)
470 		break;
471 	      limb = up[i];
472 	      bit = GMP_NUMB_HIGHBIT;
473 	    }
474 
475 	  if (bit & limb)
476 	    {
477 	      new_d = d + factor;
478 	      FORCE_DOUBLE (new_d);
479 	      diff = new_d - d;
480 	      if (diff != factor)
481 		break;	 /* rounding occured, stop now */
482 	      d = new_d;
483 	    }
484 	}
485 
486     generic_done:
487       return (sign >= 0 ? d : -d);
488     }
489 #endif
490 }
491