xref: /dflybsd-src/contrib/mpfr/src/set_ld.c (revision 2786097444a0124b5d33763854de247e230c6629)
14a238c70SJohn Marino /* mpfr_set_ld -- convert a machine long double to
24a238c70SJohn Marino                   a multiple precision floating-point number
34a238c70SJohn Marino 
4*ab6d115fSJohn Marino Copyright 2002, 2003, 2004, 2005, 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>
254a238c70SJohn Marino 
264a238c70SJohn Marino #define MPFR_NEED_LONGLONG_H
274a238c70SJohn Marino #include "mpfr-impl.h"
284a238c70SJohn Marino 
294a238c70SJohn Marino /* Various i386 systems have been seen with <float.h> LDBL constants equal
304a238c70SJohn Marino    to the DBL ones, whereas they ought to be bigger, reflecting the 10-byte
314a238c70SJohn Marino    IEEE extended format on that processor.  gcc 3.2.1 on FreeBSD and Solaris
324a238c70SJohn Marino    has been seen with the problem, and gcc 2.95.4 on FreeBSD 4.7.  */
334a238c70SJohn Marino 
344a238c70SJohn Marino #if HAVE_LDOUBLE_IEEE_EXT_LITTLE
354a238c70SJohn Marino static const union {
364a238c70SJohn Marino   char         bytes[10];
374a238c70SJohn Marino   long double  d;
384a238c70SJohn Marino } ldbl_max_struct = {
394a238c70SJohn Marino   { '\377','\377','\377','\377',
404a238c70SJohn Marino     '\377','\377','\377','\377',
414a238c70SJohn Marino     '\376','\177' }
424a238c70SJohn Marino };
434a238c70SJohn Marino #define MPFR_LDBL_MAX   (ldbl_max_struct.d)
444a238c70SJohn Marino #else
454a238c70SJohn Marino #define MPFR_LDBL_MAX   LDBL_MAX
464a238c70SJohn Marino #endif
474a238c70SJohn Marino 
484a238c70SJohn Marino #ifndef HAVE_LDOUBLE_IEEE_EXT_LITTLE
494a238c70SJohn Marino 
504a238c70SJohn Marino /* Generic code */
514a238c70SJohn Marino int
mpfr_set_ld(mpfr_ptr r,long double d,mpfr_rnd_t rnd_mode)524a238c70SJohn Marino mpfr_set_ld (mpfr_ptr r, long double d, mpfr_rnd_t rnd_mode)
534a238c70SJohn Marino {
544a238c70SJohn Marino   mpfr_t t, u;
554a238c70SJohn Marino   int inexact, shift_exp;
564a238c70SJohn Marino   long double x;
574a238c70SJohn Marino   MPFR_SAVE_EXPO_DECL (expo);
584a238c70SJohn Marino 
594a238c70SJohn Marino   /* Check for NAN */
604a238c70SJohn Marino   LONGDOUBLE_NAN_ACTION (d, goto nan);
614a238c70SJohn Marino 
624a238c70SJohn Marino   /* Check for INF */
634a238c70SJohn Marino   if (d > MPFR_LDBL_MAX)
644a238c70SJohn Marino     {
654a238c70SJohn Marino       mpfr_set_inf (r, 1);
664a238c70SJohn Marino       return 0;
674a238c70SJohn Marino     }
684a238c70SJohn Marino   else if (d < -MPFR_LDBL_MAX)
694a238c70SJohn Marino     {
704a238c70SJohn Marino       mpfr_set_inf (r, -1);
714a238c70SJohn Marino       return 0;
724a238c70SJohn Marino     }
734a238c70SJohn Marino   /* Check for ZERO */
744a238c70SJohn Marino   else if (d == 0.0)
754a238c70SJohn Marino     return mpfr_set_d (r, (double) d, rnd_mode);
764a238c70SJohn Marino 
774a238c70SJohn Marino   mpfr_init2 (t, MPFR_LDBL_MANT_DIG);
784a238c70SJohn Marino   mpfr_init2 (u, IEEE_DBL_MANT_DIG);
794a238c70SJohn Marino 
804a238c70SJohn Marino   MPFR_SAVE_EXPO_MARK (expo);
814a238c70SJohn Marino 
824a238c70SJohn Marino  convert:
834a238c70SJohn Marino   x = d;
844a238c70SJohn Marino   MPFR_SET_ZERO (t);  /* The sign doesn't matter. */
854a238c70SJohn Marino   shift_exp = 0; /* invariant: remainder to deal with is d*2^shift_exp */
864a238c70SJohn Marino   while (x != (long double) 0.0)
874a238c70SJohn Marino     {
884a238c70SJohn Marino       /* Check overflow of double */
894a238c70SJohn Marino       if (x > (long double) DBL_MAX || (-x) > (long double) DBL_MAX)
904a238c70SJohn Marino         {
914a238c70SJohn Marino           long double div9, div10, div11, div12, div13;
924a238c70SJohn Marino 
934a238c70SJohn Marino #define TWO_64 18446744073709551616.0 /* 2^64 */
944a238c70SJohn Marino #define TWO_128 (TWO_64 * TWO_64)
954a238c70SJohn Marino #define TWO_256 (TWO_128 * TWO_128)
964a238c70SJohn Marino           div9 = (long double) (double) (TWO_256 * TWO_256); /* 2^(2^9) */
974a238c70SJohn Marino           div10 = div9 * div9;
984a238c70SJohn Marino           div11 = div10 * div10; /* 2^(2^11) */
994a238c70SJohn Marino           div12 = div11 * div11; /* 2^(2^12) */
1004a238c70SJohn Marino           div13 = div12 * div12; /* 2^(2^13) */
1014a238c70SJohn Marino           if (ABS (x) >= div13)
1024a238c70SJohn Marino             {
1034a238c70SJohn Marino               x /= div13; /* exact */
1044a238c70SJohn Marino               shift_exp += 8192;
1054a238c70SJohn Marino               mpfr_div_2si (t, t, 8192, MPFR_RNDZ);
1064a238c70SJohn Marino             }
1074a238c70SJohn Marino           if (ABS (x) >= div12)
1084a238c70SJohn Marino             {
1094a238c70SJohn Marino               x /= div12; /* exact */
1104a238c70SJohn Marino               shift_exp += 4096;
1114a238c70SJohn Marino               mpfr_div_2si (t, t, 4096, MPFR_RNDZ);
1124a238c70SJohn Marino             }
1134a238c70SJohn Marino           if (ABS (x) >= div11)
1144a238c70SJohn Marino             {
1154a238c70SJohn Marino               x /= div11; /* exact */
1164a238c70SJohn Marino               shift_exp += 2048;
1174a238c70SJohn Marino               mpfr_div_2si (t, t, 2048, MPFR_RNDZ);
1184a238c70SJohn Marino             }
1194a238c70SJohn Marino           if (ABS (x) >= div10)
1204a238c70SJohn Marino             {
1214a238c70SJohn Marino               x /= div10; /* exact */
1224a238c70SJohn Marino               shift_exp += 1024;
1234a238c70SJohn Marino               mpfr_div_2si (t, t, 1024, MPFR_RNDZ);
1244a238c70SJohn Marino             }
1254a238c70SJohn Marino           /* warning: we may have DBL_MAX=2^1024*(1-2^(-53)) < x < 2^1024,
1264a238c70SJohn Marino              therefore we have one extra exponent reduction step */
1274a238c70SJohn Marino           if (ABS (x) >= div9)
1284a238c70SJohn Marino             {
1294a238c70SJohn Marino               x /= div9; /* exact */
1304a238c70SJohn Marino               shift_exp += 512;
1314a238c70SJohn Marino               mpfr_div_2si (t, t, 512, MPFR_RNDZ);
1324a238c70SJohn Marino             }
1334a238c70SJohn Marino         } /* Check overflow of double */
1344a238c70SJohn Marino       else /* no overflow on double */
1354a238c70SJohn Marino         {
1364a238c70SJohn Marino           long double div9, div10, div11;
1374a238c70SJohn Marino 
1384a238c70SJohn Marino           div9 = (long double) (double) 7.4583407312002067432909653e-155;
1394a238c70SJohn Marino           /* div9 = 2^(-2^9) */
1404a238c70SJohn Marino           div10 = div9  * div9;  /* 2^(-2^10) */
1414a238c70SJohn Marino           div11 = div10 * div10; /* 2^(-2^11) if extended precision */
1424a238c70SJohn Marino           /* since -DBL_MAX <= x <= DBL_MAX, the cast to double should not
1434a238c70SJohn Marino              overflow here */
1444a238c70SJohn Marino           if (ABS(x) < div10 &&
1454a238c70SJohn Marino               div11 != (long double) 0.0 &&
1464a238c70SJohn Marino               div11 / div10 == div10) /* possible underflow */
1474a238c70SJohn Marino             {
1484a238c70SJohn Marino               long double div12, div13;
1494a238c70SJohn Marino               /* After the divisions, any bit of x must be >= div10,
1504a238c70SJohn Marino                  hence the possible division by div9. */
1514a238c70SJohn Marino               div12 = div11 * div11; /* 2^(-2^12) */
1524a238c70SJohn Marino               div13 = div12 * div12; /* 2^(-2^13) */
1534a238c70SJohn Marino               if (ABS (x) <= div13)
1544a238c70SJohn Marino                 {
1554a238c70SJohn Marino                   x /= div13; /* exact */
1564a238c70SJohn Marino                   shift_exp -= 8192;
1574a238c70SJohn Marino                   mpfr_mul_2si (t, t, 8192, MPFR_RNDZ);
1584a238c70SJohn Marino                 }
1594a238c70SJohn Marino               if (ABS (x) <= div12)
1604a238c70SJohn Marino                 {
1614a238c70SJohn Marino                   x /= div12; /* exact */
1624a238c70SJohn Marino                   shift_exp -= 4096;
1634a238c70SJohn Marino                   mpfr_mul_2si (t, t, 4096, MPFR_RNDZ);
1644a238c70SJohn Marino                 }
1654a238c70SJohn Marino               if (ABS (x) <= div11)
1664a238c70SJohn Marino                 {
1674a238c70SJohn Marino                   x /= div11; /* exact */
1684a238c70SJohn Marino                   shift_exp -= 2048;
1694a238c70SJohn Marino                   mpfr_mul_2si (t, t, 2048, MPFR_RNDZ);
1704a238c70SJohn Marino                 }
1714a238c70SJohn Marino               if (ABS (x) <= div10)
1724a238c70SJohn Marino                 {
1734a238c70SJohn Marino                   x /= div10; /* exact */
1744a238c70SJohn Marino                   shift_exp -= 1024;
1754a238c70SJohn Marino                   mpfr_mul_2si (t, t, 1024, MPFR_RNDZ);
1764a238c70SJohn Marino                 }
1774a238c70SJohn Marino               if (ABS(x) <= div9)
1784a238c70SJohn Marino                 {
1794a238c70SJohn Marino                   x /= div9;  /* exact */
1804a238c70SJohn Marino                   shift_exp -= 512;
1814a238c70SJohn Marino                   mpfr_mul_2si (t, t, 512, MPFR_RNDZ);
1824a238c70SJohn Marino                 }
1834a238c70SJohn Marino             }
1844a238c70SJohn Marino           else /* no underflow */
1854a238c70SJohn Marino             {
1864a238c70SJohn Marino               inexact = mpfr_set_d (u, (double) x, MPFR_RNDZ);
1874a238c70SJohn Marino               MPFR_ASSERTD (inexact == 0);
1884a238c70SJohn Marino               if (mpfr_add (t, t, u, MPFR_RNDZ) != 0)
1894a238c70SJohn Marino                 {
1904a238c70SJohn Marino                   if (!mpfr_number_p (t))
1914a238c70SJohn Marino                     break;
1924a238c70SJohn Marino                   /* Inexact. This cannot happen unless the C implementation
1934a238c70SJohn Marino                      "lies" on the precision or when long doubles are
1944a238c70SJohn Marino                      implemented with FP expansions like under Mac OS X. */
1954a238c70SJohn Marino                   if (MPFR_PREC (t) != MPFR_PREC (r) + 1)
1964a238c70SJohn Marino                     {
1974a238c70SJohn Marino                       /* We assume that MPFR_PREC (r) < MPFR_PREC_MAX.
1984a238c70SJohn Marino                          The precision MPFR_PREC (r) + 1 allows us to
1994a238c70SJohn Marino                          deduce the rounding bit and the sticky bit. */
2004a238c70SJohn Marino                       mpfr_set_prec (t, MPFR_PREC (r) + 1);
2014a238c70SJohn Marino                       goto convert;
2024a238c70SJohn Marino                     }
2034a238c70SJohn Marino                   else
2044a238c70SJohn Marino                     {
2054a238c70SJohn Marino                       mp_limb_t *tp;
2064a238c70SJohn Marino                       int rb_mask;
2074a238c70SJohn Marino 
2084a238c70SJohn Marino                       /* Since mpfr_add was inexact, the sticky bit is 1. */
2094a238c70SJohn Marino                       tp = MPFR_MANT (t);
2104a238c70SJohn Marino                       rb_mask = MPFR_LIMB_ONE <<
2114a238c70SJohn Marino                         (GMP_NUMB_BITS - 1 -
2124a238c70SJohn Marino                          (MPFR_PREC (r) & (GMP_NUMB_BITS - 1)));
2134a238c70SJohn Marino                       if (rnd_mode == MPFR_RNDN)
2144a238c70SJohn Marino                         rnd_mode = (*tp & rb_mask) ^ MPFR_IS_NEG (t) ?
2154a238c70SJohn Marino                           MPFR_RNDU : MPFR_RNDD;
2164a238c70SJohn Marino                       *tp |= rb_mask;
2174a238c70SJohn Marino                       break;
2184a238c70SJohn Marino                     }
2194a238c70SJohn Marino                 }
2204a238c70SJohn Marino               x -= (long double) mpfr_get_d1 (u); /* exact */
2214a238c70SJohn Marino             }
2224a238c70SJohn Marino         }
2234a238c70SJohn Marino     }
2244a238c70SJohn Marino   inexact = mpfr_mul_2si (r, t, shift_exp, rnd_mode);
2254a238c70SJohn Marino   mpfr_clear (t);
2264a238c70SJohn Marino   mpfr_clear (u);
2274a238c70SJohn Marino 
2284a238c70SJohn Marino   MPFR_SAVE_EXPO_FREE (expo);
2294a238c70SJohn Marino   return mpfr_check_range (r, inexact, rnd_mode);
2304a238c70SJohn Marino 
2314a238c70SJohn Marino  nan:
2324a238c70SJohn Marino   MPFR_SET_NAN(r);
2334a238c70SJohn Marino   MPFR_RET_NAN;
2344a238c70SJohn Marino }
2354a238c70SJohn Marino 
2364a238c70SJohn Marino #else /* IEEE Extended Little Endian Code */
2374a238c70SJohn Marino 
2384a238c70SJohn Marino int
mpfr_set_ld(mpfr_ptr r,long double d,mpfr_rnd_t rnd_mode)2394a238c70SJohn Marino mpfr_set_ld (mpfr_ptr r, long double d, mpfr_rnd_t rnd_mode)
2404a238c70SJohn Marino {
2414a238c70SJohn Marino   int inexact, i, k, cnt;
2424a238c70SJohn Marino   mpfr_t tmp;
2434a238c70SJohn Marino   mp_limb_t tmpmant[MPFR_LIMBS_PER_LONG_DOUBLE];
2444a238c70SJohn Marino   mpfr_long_double_t x;
2454a238c70SJohn Marino   mpfr_exp_t exp;
2464a238c70SJohn Marino   int signd;
2474a238c70SJohn Marino   MPFR_SAVE_EXPO_DECL (expo);
2484a238c70SJohn Marino 
2494a238c70SJohn Marino   /* Check for NAN */
2504a238c70SJohn Marino   if (MPFR_UNLIKELY (d != d))
2514a238c70SJohn Marino     {
2524a238c70SJohn Marino       MPFR_SET_NAN (r);
2534a238c70SJohn Marino       MPFR_RET_NAN;
2544a238c70SJohn Marino     }
2554a238c70SJohn Marino   /* Check for INF */
2564a238c70SJohn Marino   else if (MPFR_UNLIKELY (d > MPFR_LDBL_MAX))
2574a238c70SJohn Marino     {
2584a238c70SJohn Marino       MPFR_SET_INF (r);
2594a238c70SJohn Marino       MPFR_SET_POS (r);
2604a238c70SJohn Marino       return 0;
2614a238c70SJohn Marino     }
2624a238c70SJohn Marino   else if (MPFR_UNLIKELY (d < -MPFR_LDBL_MAX))
2634a238c70SJohn Marino     {
2644a238c70SJohn Marino       MPFR_SET_INF (r);
2654a238c70SJohn Marino       MPFR_SET_NEG (r);
2664a238c70SJohn Marino       return 0;
2674a238c70SJohn Marino     }
2684a238c70SJohn Marino   /* Check for ZERO */
2694a238c70SJohn Marino   else if (MPFR_UNLIKELY (d == 0.0))
2704a238c70SJohn Marino     {
2714a238c70SJohn Marino       x.ld = d;
2724a238c70SJohn Marino       MPFR_SET_ZERO (r);
2734a238c70SJohn Marino       if (x.s.sign == 1)
2744a238c70SJohn Marino         MPFR_SET_NEG(r);
2754a238c70SJohn Marino       else
2764a238c70SJohn Marino         MPFR_SET_POS(r);
2774a238c70SJohn Marino       return 0;
2784a238c70SJohn Marino     }
2794a238c70SJohn Marino 
2804a238c70SJohn Marino   /* now d is neither 0, nor NaN nor Inf */
2814a238c70SJohn Marino   MPFR_SAVE_EXPO_MARK (expo);
2824a238c70SJohn Marino 
2834a238c70SJohn Marino   MPFR_MANT (tmp) = tmpmant;
2844a238c70SJohn Marino   MPFR_PREC (tmp) = 64;
2854a238c70SJohn Marino 
2864a238c70SJohn Marino   /* Extract sign */
2874a238c70SJohn Marino   x.ld = d;
2884a238c70SJohn Marino   signd = MPFR_SIGN_POS;
2894a238c70SJohn Marino   if (x.ld < 0.0)
2904a238c70SJohn Marino     {
2914a238c70SJohn Marino       signd = MPFR_SIGN_NEG;
2924a238c70SJohn Marino       x.ld = -x.ld;
2934a238c70SJohn Marino     }
2944a238c70SJohn Marino 
2954a238c70SJohn Marino   /* Extract mantissa */
2964a238c70SJohn Marino #if GMP_NUMB_BITS >= 64
2974a238c70SJohn Marino   tmpmant[0] = ((mp_limb_t) x.s.manh << 32) | ((mp_limb_t) x.s.manl);
2984a238c70SJohn Marino #else
2994a238c70SJohn Marino   tmpmant[0] = (mp_limb_t) x.s.manl;
3004a238c70SJohn Marino   tmpmant[1] = (mp_limb_t) x.s.manh;
3014a238c70SJohn Marino #endif
3024a238c70SJohn Marino 
3034a238c70SJohn Marino   /* Normalize mantissa */
3044a238c70SJohn Marino   i = MPFR_LIMBS_PER_LONG_DOUBLE;
3054a238c70SJohn Marino   MPN_NORMALIZE_NOT_ZERO (tmpmant, i);
3064a238c70SJohn Marino   k = MPFR_LIMBS_PER_LONG_DOUBLE - i;
3074a238c70SJohn Marino   count_leading_zeros (cnt, tmpmant[i - 1]);
3084a238c70SJohn Marino   if (MPFR_LIKELY (cnt != 0))
3094a238c70SJohn Marino     mpn_lshift (tmpmant + k, tmpmant, i, cnt);
3104a238c70SJohn Marino   else if (k != 0)
3114a238c70SJohn Marino     MPN_COPY (tmpmant + k, tmpmant, i);
3124a238c70SJohn Marino   if (MPFR_UNLIKELY (k != 0))
3134a238c70SJohn Marino     MPN_ZERO (tmpmant, k);
3144a238c70SJohn Marino 
3154a238c70SJohn Marino   /* Set exponent */
3164a238c70SJohn Marino   exp = (mpfr_exp_t) ((x.s.exph << 8) + x.s.expl);  /* 15-bit unsigned int */
3174a238c70SJohn Marino   if (MPFR_UNLIKELY (exp == 0))
3184a238c70SJohn Marino     exp -= 0x3FFD;
3194a238c70SJohn Marino   else
3204a238c70SJohn Marino     exp -= 0x3FFE;
3214a238c70SJohn Marino 
3224a238c70SJohn Marino   MPFR_SET_EXP (tmp, exp - cnt - k * GMP_NUMB_BITS);
3234a238c70SJohn Marino 
3244a238c70SJohn Marino   /* tmp is exact */
3254a238c70SJohn Marino   inexact = mpfr_set4 (r, tmp, rnd_mode, signd);
3264a238c70SJohn Marino 
3274a238c70SJohn Marino   MPFR_SAVE_EXPO_FREE (expo);
3284a238c70SJohn Marino   return mpfr_check_range (r, inexact, rnd_mode);
3294a238c70SJohn Marino }
3304a238c70SJohn Marino 
3314a238c70SJohn Marino #endif
332