Viewing file: set_float128.c (3.82 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* mpfr_set_float128 -- convert a machine _Float128 number to a multiple precision floating-point number
Copyright 2012-2020 Free Software Foundation, Inc. Contributed by the AriC and Caramba projects, INRIA.
This file is part of the GNU MPFR Library.
The GNU MPFR Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
The GNU MPFR Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
#define MPFR_NEED_LONGLONG_H #include "mpfr-impl.h"
#ifdef MPFR_WANT_FLOAT128
#if MPFR_WANT_FLOAT128 == 1 /* _Float128 type from ISO/IEC TS 18661 */ # define MPFR_FLOAT128_MAX 0x1.ffffffffffffffffffffffffffffp+16383f128 #elif MPFR_WANT_FLOAT128 == 2 /* __float128 type (GNU C extension) */ # define MPFR_FLOAT128_MAX 0x1.ffffffffffffffffffffffffffffp+16383q #else # error "Unsupported value for MPFR_WANT_FLOAT128" #endif
int mpfr_set_float128 (mpfr_ptr r, _Float128 d, mpfr_rnd_t rnd_mode) { mpfr_t t; mp_limb_t *tp; int inexact, shift_exp, neg, e, i; _Float128 p[14], q[14]; MPFR_SAVE_EXPO_DECL (expo);
/* Check for NaN */ if (MPFR_UNLIKELY (DOUBLE_ISNAN (d))) { MPFR_SET_NAN(r); MPFR_RET_NAN; }
/* Check for INF */ if (MPFR_UNLIKELY (d > MPFR_FLOAT128_MAX)) { MPFR_SET_INF (r); MPFR_SET_POS (r); return 0; } else if (MPFR_UNLIKELY (d < -MPFR_FLOAT128_MAX)) { MPFR_SET_INF (r); MPFR_SET_NEG (r); return 0; } /* Check for ZERO */ else if (MPFR_UNLIKELY (d == (_Float128) 0.0)) return mpfr_set_d (r, (double) d, rnd_mode);
shift_exp = 0; /* invariant: remainder to deal with is d*2^shift_exp */ neg = d < 0; if (d < 0) d = -d;
/* Scaling, avoiding (slow) divisions. Should the tables be cached? */ if (d >= 1.0) { p[0] = 2.0; q[0] = 0.5; e = 1; /* p[i] = 2^(2^i), q[i] = 1/p[i] */ for (i = 0; i < 13 && d >= p[i]; i++) { p[i+1] = p[i] * p[i]; q[i+1] = q[i] * q[i]; e <<= 1; } for (; i >= 0; e >>= 1, i--) if (d >= p[i]) { d *= q[i]; shift_exp += e; } d *= 0.5; shift_exp++; } else if (d < 0.5) { p[0] = 2.0; q[0] = 0.5; e = 1; /* p[i] = 2^(2^i), q[i] = 1/p[i] */ for (i = 0; i < 13 && d < q[i]; i++) { p[i+1] = p[i] * p[i]; q[i+1] = q[i] * q[i]; e <<= 1; } /* The while() may be needed for i = 13 due to subnormals. This can probably be improved without yielding an underflow. */ for (; i >= 0; e >>= 1, i--) while (d < q[i]) { d *= p[i]; shift_exp -= e; } }
MPFR_ASSERTD (d >= 0.5 && d < 1.0);
mpfr_init2 (t, IEEE_FLOAT128_MANT_DIG); tp = MPFR_MANT (t);
MPFR_SAVE_EXPO_MARK (expo); MPFR_SET_EXP (t, shift_exp); MPFR_SET_SIGN (t, neg ? MPFR_SIGN_NEG : MPFR_SIGN_POS);
for (i = MPFR_LAST_LIMB (t); i >= 0; i--) { d *= 2 * (_Float128) MPFR_LIMB_HIGHBIT; tp[i] = (mp_limb_t) d; d -= tp[i]; }
inexact = mpfr_set (r, t, rnd_mode); mpfr_clear (t);
MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (r, inexact, rnd_mode); }
#endif /* MPFR_WANT_FLOAT128 */
|