1299c6f0cSmrg /* mpfr_get_float128 -- convert a multiple precision floating-point
22ba2404bSmrg number to a _Float128 number
3299c6f0cSmrg
4*ba125506Smrg Copyright 2012-2023 Free Software Foundation, Inc.
5299c6f0cSmrg Contributed by the AriC and Caramba projects, INRIA.
6299c6f0cSmrg
7299c6f0cSmrg This file is part of the GNU MPFR Library.
8299c6f0cSmrg
9299c6f0cSmrg The GNU MPFR Library is free software; you can redistribute it and/or modify
10299c6f0cSmrg it under the terms of the GNU Lesser General Public License as published by
11299c6f0cSmrg the Free Software Foundation; either version 3 of the License, or (at your
12299c6f0cSmrg option) any later version.
13299c6f0cSmrg
14299c6f0cSmrg The GNU MPFR Library is distributed in the hope that it will be useful, but
15299c6f0cSmrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16299c6f0cSmrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17299c6f0cSmrg License for more details.
18299c6f0cSmrg
19299c6f0cSmrg You should have received a copy of the GNU Lesser General Public License
20299c6f0cSmrg along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
212ba2404bSmrg https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
22299c6f0cSmrg 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
23299c6f0cSmrg
24299c6f0cSmrg #include "mpfr-impl.h"
25299c6f0cSmrg
26299c6f0cSmrg #ifdef MPFR_WANT_FLOAT128
27299c6f0cSmrg
28299c6f0cSmrg /* generic code */
292ba2404bSmrg _Float128
mpfr_get_float128(mpfr_srcptr x,mpfr_rnd_t rnd_mode)30299c6f0cSmrg mpfr_get_float128 (mpfr_srcptr x, mpfr_rnd_t rnd_mode)
31299c6f0cSmrg {
32299c6f0cSmrg
33299c6f0cSmrg if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
342ba2404bSmrg return (_Float128) mpfr_get_d (x, rnd_mode);
35299c6f0cSmrg else /* now x is a normal non-zero number */
36299c6f0cSmrg {
372ba2404bSmrg _Float128 r; /* result */
382ba2404bSmrg _Float128 m;
39299c6f0cSmrg mpfr_exp_t e; /* exponent of x (before rounding) */
40299c6f0cSmrg mpfr_exp_t sh; /* exponent shift, so that x/2^sh is in the double range */
41299c6f0cSmrg const int emin = -16381;
42299c6f0cSmrg const int esub = emin - IEEE_FLOAT128_MANT_DIG;
43299c6f0cSmrg int sign;
44299c6f0cSmrg
45299c6f0cSmrg sign = MPFR_SIGN (x);
46299c6f0cSmrg e = MPFR_GET_EXP (x);
47299c6f0cSmrg
48299c6f0cSmrg if (MPFR_UNLIKELY (e <= esub))
49299c6f0cSmrg {
50299c6f0cSmrg if (MPFR_IS_LIKE_RNDZ (rnd_mode, sign < 0) ||
51299c6f0cSmrg (rnd_mode == MPFR_RNDN && (e < esub || mpfr_powerof2_raw (x))))
52299c6f0cSmrg return sign < 0 ? -0.0 : 0.0;
53299c6f0cSmrg r = 1.0;
54299c6f0cSmrg sh = esub;
55299c6f0cSmrg }
56299c6f0cSmrg else
57299c6f0cSmrg {
58299c6f0cSmrg mpfr_t y;
59299c6f0cSmrg mp_limb_t *yp;
60299c6f0cSmrg int prec, i; /* small enough to fit in an int */
61299c6f0cSmrg MPFR_SAVE_EXPO_DECL (expo);
62299c6f0cSmrg
63299c6f0cSmrg MPFR_SAVE_EXPO_MARK (expo);
64299c6f0cSmrg
652ba2404bSmrg /* First round x to the target _Float128 precision, taking the
66299c6f0cSmrg reduced precision of the subnormals into account, so that all
67299c6f0cSmrg subsequent operations are exact (this avoids double rounding
68299c6f0cSmrg problems). */
69299c6f0cSmrg prec = e < emin ? e - esub : IEEE_FLOAT128_MANT_DIG;
70299c6f0cSmrg MPFR_ASSERTD (prec >= MPFR_PREC_MIN);
71299c6f0cSmrg mpfr_init2 (y, prec);
72299c6f0cSmrg
73299c6f0cSmrg mpfr_set (y, x, rnd_mode);
74299c6f0cSmrg sh = MPFR_GET_EXP (y);
75299c6f0cSmrg MPFR_SET_EXP (y, 0);
76299c6f0cSmrg MPFR_SET_POS (y);
77299c6f0cSmrg yp = MPFR_MANT (y);
78299c6f0cSmrg
79299c6f0cSmrg r = 0.0;
80299c6f0cSmrg for (i = 0; i < MPFR_LIMB_SIZE (y); i++)
81299c6f0cSmrg {
82299c6f0cSmrg /* Note: MPFR_LIMB_MAX is avoided below as it might not
83299c6f0cSmrg always work if GMP_NUMB_BITS > IEEE_FLOAT128_MANT_DIG.
84299c6f0cSmrg MPFR_LIMB_HIGHBIT has the advantage to fit on 1 bit. */
85299c6f0cSmrg r += yp[i];
862ba2404bSmrg r *= 1 / (2 * (_Float128) MPFR_LIMB_HIGHBIT);
87299c6f0cSmrg }
88299c6f0cSmrg
89299c6f0cSmrg mpfr_clear (y);
90299c6f0cSmrg
91299c6f0cSmrg MPFR_SAVE_EXPO_FREE (expo);
92299c6f0cSmrg }
93299c6f0cSmrg
94299c6f0cSmrg /* we now have to multiply r by 2^sh */
95299c6f0cSmrg MPFR_ASSERTD (r > 0);
96299c6f0cSmrg if (sh != 0)
97299c6f0cSmrg {
98299c6f0cSmrg /* An overflow may occur (example: 0.5*2^1024) */
99299c6f0cSmrg while (r < 1.0)
100299c6f0cSmrg {
101299c6f0cSmrg r += r;
102299c6f0cSmrg sh--;
103299c6f0cSmrg }
104299c6f0cSmrg
105299c6f0cSmrg if (sh > 0)
106299c6f0cSmrg m = 2.0;
107299c6f0cSmrg else
108299c6f0cSmrg {
109299c6f0cSmrg m = 0.5;
110299c6f0cSmrg sh = -sh;
111299c6f0cSmrg }
112299c6f0cSmrg
113299c6f0cSmrg for (;;)
114299c6f0cSmrg {
115299c6f0cSmrg if (sh % 2)
116299c6f0cSmrg r = r * m;
117299c6f0cSmrg sh >>= 1;
118299c6f0cSmrg if (sh == 0)
119299c6f0cSmrg break;
120299c6f0cSmrg m = m * m;
121299c6f0cSmrg }
122299c6f0cSmrg }
123299c6f0cSmrg if (sign < 0)
124299c6f0cSmrg r = -r;
125299c6f0cSmrg return r;
126299c6f0cSmrg }
127299c6f0cSmrg }
128299c6f0cSmrg
129299c6f0cSmrg #endif /* MPFR_WANT_FLOAT128 */
130