xref: /dflybsd-src/contrib/mpfr/src/set_d.c (revision 2786097444a0124b5d33763854de247e230c6629)
14a238c70SJohn Marino /* mpfr_set_d -- convert a machine double precision float to
24a238c70SJohn Marino                  a multiple precision floating-point number
34a238c70SJohn Marino 
4*ab6d115fSJohn Marino Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
5*ab6d115fSJohn Marino Contributed by the AriC and Caramel projects, INRIA.
64a238c70SJohn Marino 
74a238c70SJohn Marino This file is part of the GNU MPFR Library.
84a238c70SJohn Marino 
94a238c70SJohn Marino The GNU MPFR Library is free software; you can redistribute it and/or modify
104a238c70SJohn Marino it under the terms of the GNU Lesser General Public License as published by
114a238c70SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
124a238c70SJohn Marino option) any later version.
134a238c70SJohn Marino 
144a238c70SJohn Marino The GNU MPFR Library is distributed in the hope that it will be useful, but
154a238c70SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
164a238c70SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
174a238c70SJohn Marino License for more details.
184a238c70SJohn Marino 
194a238c70SJohn Marino You should have received a copy of the GNU Lesser General Public License
204a238c70SJohn Marino along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
214a238c70SJohn Marino http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
224a238c70SJohn Marino 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
234a238c70SJohn Marino 
244a238c70SJohn Marino #include <float.h>  /* For DOUBLE_ISINF and DOUBLE_ISNAN */
254a238c70SJohn Marino 
264a238c70SJohn Marino #define MPFR_NEED_LONGLONG_H
274a238c70SJohn Marino #include "mpfr-impl.h"
284a238c70SJohn Marino 
294a238c70SJohn Marino /* extracts the bits of d in rp[0..n-1] where n=ceil(53/GMP_NUMB_BITS).
304a238c70SJohn Marino    Assumes d is neither 0 nor NaN nor Inf. */
314a238c70SJohn Marino static long
__gmpfr_extract_double(mpfr_limb_ptr rp,double d)324a238c70SJohn Marino __gmpfr_extract_double (mpfr_limb_ptr rp, double d)
334a238c70SJohn Marino      /* e=0 iff GMP_NUMB_BITS=32 and rp has only one limb */
344a238c70SJohn Marino {
354a238c70SJohn Marino   long exp;
364a238c70SJohn Marino   mp_limb_t manl;
374a238c70SJohn Marino #if GMP_NUMB_BITS == 32
384a238c70SJohn Marino   mp_limb_t manh;
394a238c70SJohn Marino #endif
404a238c70SJohn Marino 
414a238c70SJohn Marino   /* BUGS
424a238c70SJohn Marino      1. Should handle Inf and NaN in IEEE specific code.
434a238c70SJohn Marino      2. Handle Inf and NaN also in default code, to avoid hangs.
444a238c70SJohn Marino      3. Generalize to handle all GMP_NUMB_BITS.
454a238c70SJohn Marino      4. This lits is incomplete and misspelled.
464a238c70SJohn Marino    */
474a238c70SJohn Marino 
484a238c70SJohn Marino   MPFR_ASSERTD(!DOUBLE_ISNAN(d));
494a238c70SJohn Marino   MPFR_ASSERTD(!DOUBLE_ISINF(d));
504a238c70SJohn Marino   MPFR_ASSERTD(d != 0.0);
514a238c70SJohn Marino 
524a238c70SJohn Marino #if _GMP_IEEE_FLOATS
534a238c70SJohn Marino 
544a238c70SJohn Marino   {
554a238c70SJohn Marino     union ieee_double_extract x;
564a238c70SJohn Marino     x.d = d;
574a238c70SJohn Marino 
584a238c70SJohn Marino     exp = x.s.exp;
594a238c70SJohn Marino     if (exp)
604a238c70SJohn Marino       {
614a238c70SJohn Marino #if GMP_NUMB_BITS >= 64
624a238c70SJohn Marino         manl = ((MPFR_LIMB_ONE << 63)
634a238c70SJohn Marino                 | ((mp_limb_t) x.s.manh << 43) | ((mp_limb_t) x.s.manl << 11));
644a238c70SJohn Marino #else
654a238c70SJohn Marino         manh = (MPFR_LIMB_ONE << 31) | (x.s.manh << 11) | (x.s.manl >> 21);
664a238c70SJohn Marino         manl = x.s.manl << 11;
674a238c70SJohn Marino #endif
684a238c70SJohn Marino       }
694a238c70SJohn Marino     else /* denormalized number */
704a238c70SJohn Marino       {
714a238c70SJohn Marino #if GMP_NUMB_BITS >= 64
724a238c70SJohn Marino         manl = ((mp_limb_t) x.s.manh << 43) | ((mp_limb_t) x.s.manl << 11);
734a238c70SJohn Marino #else
744a238c70SJohn Marino         manh = (x.s.manh << 11) /* high 21 bits */
754a238c70SJohn Marino           | (x.s.manl >> 21); /* middle 11 bits */
764a238c70SJohn Marino         manl = x.s.manl << 11; /* low 21 bits */
774a238c70SJohn Marino #endif
784a238c70SJohn Marino       }
794a238c70SJohn Marino 
804a238c70SJohn Marino     if (exp)
814a238c70SJohn Marino       exp -= 1022;
824a238c70SJohn Marino     else
834a238c70SJohn Marino       exp = -1021;
844a238c70SJohn Marino   }
854a238c70SJohn Marino 
864a238c70SJohn Marino #else /* _GMP_IEEE_FLOATS */
874a238c70SJohn Marino 
884a238c70SJohn Marino   {
894a238c70SJohn Marino     /* Unknown (or known to be non-IEEE) double format.  */
904a238c70SJohn Marino     exp = 0;
914a238c70SJohn Marino     if (d >= 1.0)
924a238c70SJohn Marino       {
934a238c70SJohn Marino         MPFR_ASSERTN (d * 0.5 != d);
944a238c70SJohn Marino         while (d >= 32768.0)
954a238c70SJohn Marino           {
964a238c70SJohn Marino             d *= (1.0 / 65536.0);
974a238c70SJohn Marino             exp += 16;
984a238c70SJohn Marino           }
994a238c70SJohn Marino         while (d >= 1.0)
1004a238c70SJohn Marino           {
1014a238c70SJohn Marino             d *= 0.5;
1024a238c70SJohn Marino             exp += 1;
1034a238c70SJohn Marino           }
1044a238c70SJohn Marino       }
1054a238c70SJohn Marino     else if (d < 0.5)
1064a238c70SJohn Marino       {
1074a238c70SJohn Marino         while (d < (1.0 / 65536.0))
1084a238c70SJohn Marino           {
1094a238c70SJohn Marino             d *=  65536.0;
1104a238c70SJohn Marino             exp -= 16;
1114a238c70SJohn Marino           }
1124a238c70SJohn Marino         while (d < 0.5)
1134a238c70SJohn Marino           {
1144a238c70SJohn Marino             d *= 2.0;
1154a238c70SJohn Marino             exp -= 1;
1164a238c70SJohn Marino           }
1174a238c70SJohn Marino       }
1184a238c70SJohn Marino 
1194a238c70SJohn Marino     d *= MP_BASE_AS_DOUBLE;
1204a238c70SJohn Marino #if GMP_NUMB_BITS >= 64
1214a238c70SJohn Marino     manl = d;
1224a238c70SJohn Marino #else
1234a238c70SJohn Marino     manh = (mp_limb_t) d;
1244a238c70SJohn Marino     manl = (mp_limb_t) ((d - manh) * MP_BASE_AS_DOUBLE);
1254a238c70SJohn Marino #endif
1264a238c70SJohn Marino   }
1274a238c70SJohn Marino 
1284a238c70SJohn Marino #endif /* _GMP_IEEE_FLOATS */
1294a238c70SJohn Marino 
1304a238c70SJohn Marino #if GMP_NUMB_BITS >= 64
1314a238c70SJohn Marino   rp[0] = manl;
1324a238c70SJohn Marino #else
1334a238c70SJohn Marino   rp[1] = manh;
1344a238c70SJohn Marino   rp[0] = manl;
1354a238c70SJohn Marino #endif
1364a238c70SJohn Marino 
1374a238c70SJohn Marino   return exp;
1384a238c70SJohn Marino }
1394a238c70SJohn Marino 
1404a238c70SJohn Marino /* End of part included from gmp-2.0.2 */
1414a238c70SJohn Marino 
1424a238c70SJohn Marino int
mpfr_set_d(mpfr_ptr r,double d,mpfr_rnd_t rnd_mode)1434a238c70SJohn Marino mpfr_set_d (mpfr_ptr r, double d, mpfr_rnd_t rnd_mode)
1444a238c70SJohn Marino {
1454a238c70SJohn Marino   int signd, inexact;
1464a238c70SJohn Marino   unsigned int cnt;
1474a238c70SJohn Marino   mp_size_t i, k;
1484a238c70SJohn Marino   mpfr_t tmp;
1494a238c70SJohn Marino   mp_limb_t tmpmant[MPFR_LIMBS_PER_DOUBLE];
1504a238c70SJohn Marino   MPFR_SAVE_EXPO_DECL (expo);
1514a238c70SJohn Marino 
1524a238c70SJohn Marino   if (MPFR_UNLIKELY(DOUBLE_ISNAN(d)))
1534a238c70SJohn Marino     {
1544a238c70SJohn Marino       MPFR_SET_NAN(r);
1554a238c70SJohn Marino       MPFR_RET_NAN;
1564a238c70SJohn Marino     }
1574a238c70SJohn Marino   else if (MPFR_UNLIKELY(d == 0))
1584a238c70SJohn Marino     {
1594a238c70SJohn Marino #if _GMP_IEEE_FLOATS
1604a238c70SJohn Marino       union ieee_double_extract x;
1614a238c70SJohn Marino 
1624a238c70SJohn Marino       MPFR_SET_ZERO(r);
1634a238c70SJohn Marino       /* set correct sign */
1644a238c70SJohn Marino       x.d = d;
1654a238c70SJohn Marino       if (x.s.sig == 1)
1664a238c70SJohn Marino         MPFR_SET_NEG(r);
1674a238c70SJohn Marino       else
1684a238c70SJohn Marino         MPFR_SET_POS(r);
1694a238c70SJohn Marino #else /* _GMP_IEEE_FLOATS */
1704a238c70SJohn Marino       MPFR_SET_ZERO(r);
1714a238c70SJohn Marino       {
1724a238c70SJohn Marino         /* This is to get the sign of zero on non-IEEE hardware
1734a238c70SJohn Marino            Some systems support +0.0, -0.0 and unsigned zero.
1744a238c70SJohn Marino            We can't use d==+0.0 since it should be always true,
1754a238c70SJohn Marino            so we check that the memory representation of d is the
1764a238c70SJohn Marino            same than +0.0. etc */
1774a238c70SJohn Marino         /* FIXME: consider the case where +0.0 or -0.0 may have several
1784a238c70SJohn Marino            representations. */
1794a238c70SJohn Marino         double poszero = +0.0, negzero = DBL_NEG_ZERO;
1804a238c70SJohn Marino         if (memcmp(&d, &poszero, sizeof(double)) == 0)
1814a238c70SJohn Marino           MPFR_SET_POS(r);
1824a238c70SJohn Marino         else if (memcmp(&d, &negzero, sizeof(double)) == 0)
1834a238c70SJohn Marino           MPFR_SET_NEG(r);
1844a238c70SJohn Marino         else
1854a238c70SJohn Marino           MPFR_SET_POS(r);
1864a238c70SJohn Marino       }
1874a238c70SJohn Marino #endif
1884a238c70SJohn Marino       return 0; /* 0 is exact */
1894a238c70SJohn Marino     }
1904a238c70SJohn Marino   else if (MPFR_UNLIKELY(DOUBLE_ISINF(d)))
1914a238c70SJohn Marino     {
1924a238c70SJohn Marino       MPFR_SET_INF(r);
1934a238c70SJohn Marino       if (d > 0)
1944a238c70SJohn Marino         MPFR_SET_POS(r);
1954a238c70SJohn Marino       else
1964a238c70SJohn Marino         MPFR_SET_NEG(r);
1974a238c70SJohn Marino       return 0; /* infinity is exact */
1984a238c70SJohn Marino     }
1994a238c70SJohn Marino 
2004a238c70SJohn Marino   /* now d is neither 0, nor NaN nor Inf */
2014a238c70SJohn Marino 
2024a238c70SJohn Marino   MPFR_SAVE_EXPO_MARK (expo);
2034a238c70SJohn Marino 
2044a238c70SJohn Marino   /* warning: don't use tmp=r here, even if SIZE(r) >= MPFR_LIMBS_PER_DOUBLE,
2054a238c70SJohn Marino      since PREC(r) may be different from PREC(tmp), and then both variables
2064a238c70SJohn Marino      would have same precision in the mpfr_set4 call below. */
2074a238c70SJohn Marino   MPFR_MANT(tmp) = tmpmant;
2084a238c70SJohn Marino   MPFR_PREC(tmp) = IEEE_DBL_MANT_DIG;
2094a238c70SJohn Marino 
2104a238c70SJohn Marino   signd = (d < 0) ? MPFR_SIGN_NEG : MPFR_SIGN_POS;
2114a238c70SJohn Marino   d = ABS (d);
2124a238c70SJohn Marino 
2134a238c70SJohn Marino   /* don't use MPFR_SET_EXP here since the exponent may be out of range */
2144a238c70SJohn Marino   MPFR_EXP(tmp) = __gmpfr_extract_double (tmpmant, d);
2154a238c70SJohn Marino 
2164a238c70SJohn Marino #ifdef WANT_ASSERT
2174a238c70SJohn Marino   /* Failed assertion if the stored value is 0 (e.g., if the exponent range
2184a238c70SJohn Marino      has been reduced at the wrong moment and an underflow to 0 occurred).
2194a238c70SJohn Marino      Probably a bug in the C implementation if this happens. */
2204a238c70SJohn Marino   i = 0;
2214a238c70SJohn Marino   while (tmpmant[i] == 0)
2224a238c70SJohn Marino     {
2234a238c70SJohn Marino       i++;
2244a238c70SJohn Marino       MPFR_ASSERTN(i < MPFR_LIMBS_PER_DOUBLE);
2254a238c70SJohn Marino     }
2264a238c70SJohn Marino #endif
2274a238c70SJohn Marino 
2284a238c70SJohn Marino   /* determine the index i-1 of the most significant non-zero limb
2294a238c70SJohn Marino      and the number k of zero high limbs */
2304a238c70SJohn Marino   i = MPFR_LIMBS_PER_DOUBLE;
2314a238c70SJohn Marino   MPN_NORMALIZE_NOT_ZERO(tmpmant, i);
2324a238c70SJohn Marino   k = MPFR_LIMBS_PER_DOUBLE - i;
2334a238c70SJohn Marino 
2344a238c70SJohn Marino   count_leading_zeros (cnt, tmpmant[i - 1]);
2354a238c70SJohn Marino 
2364a238c70SJohn Marino   if (MPFR_LIKELY(cnt != 0))
2374a238c70SJohn Marino     mpn_lshift (tmpmant + k, tmpmant, i, cnt);
2384a238c70SJohn Marino   else if (k != 0)
2394a238c70SJohn Marino     MPN_COPY (tmpmant + k, tmpmant, i);
2404a238c70SJohn Marino 
2414a238c70SJohn Marino   if (MPFR_UNLIKELY(k != 0))
2424a238c70SJohn Marino     MPN_ZERO (tmpmant, k);
2434a238c70SJohn Marino 
2444a238c70SJohn Marino   /* don't use MPFR_SET_EXP here since the exponent may be out of range */
2454a238c70SJohn Marino   MPFR_EXP(tmp) -= (mpfr_exp_t) (cnt + k * GMP_NUMB_BITS);
2464a238c70SJohn Marino 
2474a238c70SJohn Marino   /* tmp is exact since PREC(tmp)=53 */
2484a238c70SJohn Marino   inexact = mpfr_set4 (r, tmp, rnd_mode, signd);
2494a238c70SJohn Marino 
2504a238c70SJohn Marino   MPFR_SAVE_EXPO_FREE (expo);
2514a238c70SJohn Marino   return mpfr_check_range (r, inexact, rnd_mode);
2524a238c70SJohn Marino }
2534a238c70SJohn Marino 
2544a238c70SJohn Marino 
2554a238c70SJohn Marino 
256