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