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