1 /* mpfr_get_ld, mpfr_get_ld_2exp -- convert a multiple precision floating-point
2 number to a machine long double
4 Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
5 Contributed by the Arenaire and Cacao projects, INRIA.
7 This file is part of the GNU MPFR Library.
9 The GNU MPFR Library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or (at your
12 option) any later version.
14 The GNU MPFR Library is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with the GNU MPFR Library; see the file COPYING.LIB. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
22 MA 02110-1301, USA. */
26 #include "mpfr-impl.h"
28 #ifndef HAVE_LDOUBLE_IEEE_EXT_LITTLE
31 mpfr_get_ld (mpfr_srcptr x, mp_rnd_t rnd_mode)
34 if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
35 return (long double) mpfr_get_d (x, rnd_mode);
36 else /* now x is a normal non-zero number */
38 long double r; /* result */
40 double s; /* part of result */
41 mp_exp_t sh; /* exponent shift, so that x/2^sh is in the double range */
45 /* first round x to the target long double precision, so that
46 all subsequent operations are exact (this avoids double rounding
48 mpfr_init2 (y, MPFR_LDBL_MANT_DIG);
49 mpfr_init2 (z, IEEE_DBL_MANT_DIG);
51 mpfr_set (y, x, rnd_mode);
52 sh = MPFR_GET_EXP (y);
59 s = mpfr_get_d (y, GMP_RNDN); /* high part of y */
61 mpfr_set_d (z, s, GMP_RNDN); /* exact */
62 mpfr_sub (y, y, z, GMP_RNDN); /* exact */
63 } while (!MPFR_IS_ZERO (y));
68 /* we now have to multiply back by 2^sh */
72 /* An overflow may occurs (example: 0.5*2^1024) */
106 mpfr_get_ld (mpfr_srcptr x, mp_rnd_t rnd_mode)
108 mpfr_long_double_t ld;
111 MPFR_SAVE_EXPO_DECL (expo);
113 MPFR_SAVE_EXPO_MARK (expo);
115 mpfr_init2 (tmp, MPFR_LDBL_MANT_DIG);
116 inex = mpfr_set (tmp, x, rnd_mode);
118 mpfr_set_emin (-16382-63);
119 mpfr_set_emax (16384);
120 mpfr_subnormalize (tmp, mpfr_check_range (tmp, inex, rnd_mode), rnd_mode);
121 mpfr_prec_round (tmp, 64, GMP_RNDZ); /* exact */
122 if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (tmp)))
123 ld.ld = (long double) mpfr_get_d (tmp, rnd_mode);
129 tmpmant = MPFR_MANT (tmp);
130 e = MPFR_GET_EXP (tmp);
131 /* the smallest normal number is 2^(-16382), which is 0.5*2^(-16381)
132 in MPFR, thus any exponent <= -16382 corresponds to a subnormal
134 denorm = MPFR_UNLIKELY (e <= -16382) ? - e - 16382 + 1 : 0;
135 #if BITS_PER_MP_LIMB >= 64
136 ld.s.manl = (tmpmant[0] >> denorm);
137 ld.s.manh = (tmpmant[0] >> denorm) >> 32;
138 #elif BITS_PER_MP_LIMB == 32
139 if (MPFR_LIKELY (denorm == 0))
141 ld.s.manl = tmpmant[0];
142 ld.s.manh = tmpmant[1];
144 else if (denorm < 32)
146 ld.s.manl = (tmpmant[0] >> denorm) | (tmpmant[1] << (32 - denorm));
147 ld.s.manh = tmpmant[1] >> denorm;
149 else /* 32 <= denorm <= 64 */
151 ld.s.manl = tmpmant[1] >> (denorm - 32);
155 # error "BITS_PER_MP_LIMB must be 32 or >= 64"
156 /* Other values have never been supported anyway. */
158 if (MPFR_LIKELY (denorm == 0))
160 ld.s.exph = (e + 0x3FFE) >> 8;
161 ld.s.expl = (e + 0x3FFE);
164 ld.s.exph = ld.s.expl = 0;
165 ld.s.sign = MPFR_IS_NEG (x);
169 MPFR_SAVE_EXPO_FREE (expo);
175 /* contributed by Damien Stehle */
177 mpfr_get_ld_2exp (long *expptr, mpfr_srcptr src, mp_rnd_t rnd_mode)
183 if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (src)))
184 return (long double) mpfr_get_d_2exp (expptr, src, rnd_mode);
186 tmp[0] = *src; /* Hack copy mpfr_t */
187 MPFR_SET_EXP (tmp, 0);
188 ret = mpfr_get_ld (tmp, rnd_mode);
190 if (MPFR_IS_PURE_FP(src))
192 exp = MPFR_GET_EXP (src);
194 /* rounding can give 1.0, adjust back to 0.5 <= abs(ret) < 1.0 */
200 else if (ret == -1.0)
206 MPFR_ASSERTN ((ret >= 0.5 && ret < 1.0)
207 || (ret <= -0.5 && ret > -1.0));
208 MPFR_ASSERTN (exp >= LONG_MIN && exp <= LONG_MAX);