(root)/
mpfr-4.2.1/
src/
get_ld.c
       1  /* mpfr_get_ld, mpfr_get_ld_2exp -- convert a multiple precision floating-point
       2                                      number to a machine long double
       3  
       4  Copyright 2002-2023 Free Software Foundation, Inc.
       5  Contributed by the AriC and Caramba projects, INRIA.
       6  
       7  This file is part of the GNU MPFR Library.
       8  
       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 3 of the License, or (at your
      12  option) any later version.
      13  
      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.
      18  
      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.LESSER.  If not, see
      21  https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
      22  51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
      23  
      24  #include <float.h> /* needed so that MPFR_LDBL_MANT_DIG is correctly defined */
      25  
      26  #include "mpfr-impl.h"
      27  
      28  #if defined(HAVE_LDOUBLE_IS_DOUBLE)
      29  
      30  /* special code when "long double" is the same format as "double" */
      31  long double
      32  mpfr_get_ld (mpfr_srcptr x, mpfr_rnd_t rnd_mode)
      33  {
      34    return (long double) mpfr_get_d (x, rnd_mode);
      35  }
      36  
      37  #elif defined(HAVE_LDOUBLE_IEEE_EXT_LITTLE)
      38  
      39  /* Note: The code will return a result with a 64-bit precision, even
      40     if the rounding precision is only 53 bits like on FreeBSD and
      41     NetBSD 6- (or with GCC's -mpc64 option to simulate this on other
      42     platforms). This is consistent with how strtold behaves in these
      43     cases, for instance. */
      44  
      45  /* special code for IEEE 754 little-endian extended format */
      46  long double
      47  mpfr_get_ld (mpfr_srcptr x, mpfr_rnd_t rnd_mode)
      48  {
      49    mpfr_long_double_t ld;
      50    mpfr_t tmp;
      51    int inex;
      52    MPFR_SAVE_EXPO_DECL (expo);
      53  
      54    MPFR_SAVE_EXPO_MARK (expo);
      55  
      56    mpfr_init2 (tmp, MPFR_LDBL_MANT_DIG);
      57    inex = mpfr_set (tmp, x, rnd_mode);
      58  
      59    mpfr_set_emin (-16381-63); /* emin=-16444, see below */
      60    mpfr_set_emax (16384);
      61    mpfr_subnormalize (tmp, mpfr_check_range (tmp, inex, rnd_mode), rnd_mode);
      62    mpfr_prec_round (tmp, 64, MPFR_RNDZ); /* exact */
      63    if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (tmp)))
      64      ld.ld = (long double) mpfr_get_d (tmp, rnd_mode);
      65    else
      66      {
      67        mp_limb_t *tmpmant;
      68        mpfr_exp_t e, denorm;
      69  
      70        tmpmant = MPFR_MANT (tmp);
      71        e = MPFR_GET_EXP (tmp);
      72        /* The smallest positive normal number is 2^(-16382), which is
      73           0.5*2^(-16381) in MPFR, thus any exponent <= -16382 corresponds to a
      74           subnormal number. The smallest positive subnormal number is 2^(-16445)
      75           which is 0.5*2^(-16444) in MPFR thus 0 <= denorm <= 63. */
      76        denorm = MPFR_UNLIKELY (e <= -16382) ? - e - 16382 + 1 : 0;
      77        MPFR_ASSERTD (0 <= denorm && denorm < 64);
      78  #if GMP_NUMB_BITS >= 64
      79        ld.s.manl = (tmpmant[0] >> denorm);
      80        ld.s.manh = (tmpmant[0] >> denorm) >> 32;
      81  #elif GMP_NUMB_BITS == 32
      82        if (MPFR_LIKELY (denorm == 0))
      83          {
      84            ld.s.manl = tmpmant[0];
      85            ld.s.manh = tmpmant[1];
      86          }
      87        else if (denorm < 32)
      88          {
      89            ld.s.manl = (tmpmant[0] >> denorm) | (tmpmant[1] << (32 - denorm));
      90            ld.s.manh = tmpmant[1] >> denorm;
      91          }
      92        else /* 32 <= denorm < 64 */
      93          {
      94            ld.s.manl = tmpmant[1] >> (denorm - 32);
      95            ld.s.manh = 0;
      96          }
      97  #elif GMP_NUMB_BITS == 16
      98        if (MPFR_LIKELY (denorm == 0))
      99          {
     100            /* manl = tmpmant[1] | tmpmant[0]
     101               manh = tmpmant[3] | tmpmant[2] */
     102            ld.s.manl = tmpmant[0] | ((unsigned long) tmpmant[1] << 16);
     103            ld.s.manh = tmpmant[2] | ((unsigned long) tmpmant[3] << 16);
     104          }
     105        else if (denorm < 16)
     106          {
     107            /* manl = low(mant[2],denorm) | mant[1] | high(mant[0],16-denorm)
     108               manh = mant[3] | high(mant[2],16-denorm) */
     109            ld.s.manl = (tmpmant[0] >> denorm)
     110              | ((unsigned long) tmpmant[1] << (16 - denorm))
     111              | ((unsigned long) tmpmant[2] << (32 - denorm));
     112            ld.s.manh = (tmpmant[2] >> denorm)
     113              | ((unsigned long) tmpmant[3] << (16 - denorm));
     114          }
     115        else if (denorm == 16)
     116          {
     117            /* manl = tmpmant[2] | tmpmant[1]
     118               manh = 0000000000 | tmpmant[3] */
     119            ld.s.manl = tmpmant[1] | ((unsigned long) tmpmant[2] << 16);
     120            ld.s.manh = tmpmant[3];
     121          }
     122        else if (denorm < 32)
     123          {
     124            /* manl = low(mant[3],denorm-16) | mant[2] | high(mant[1],32-denorm)
     125               manh = high(mant[3],32-denorm) */
     126            ld.s.manl = (tmpmant[1] >> (denorm - 16))
     127              | ((unsigned long) tmpmant[2] << (32 - denorm))
     128              | ((unsigned long) tmpmant[3] << (48 - denorm));
     129            ld.s.manh = tmpmant[3] >> (denorm - 16);
     130          }
     131        else if (denorm == 32)
     132          {
     133            /* manl = tmpmant[3] | tmpmant[2]
     134               manh = 0 */
     135            ld.s.manl = tmpmant[2] | ((unsigned long) tmpmant[3] << 16);
     136            ld.s.manh = 0;
     137          }
     138        else if (denorm < 48)
     139          {
     140            /* manl = zero(denorm-32) | tmpmant[3] | high(tmpmant[2],48-denorm)
     141               manh = 0 */
     142            ld.s.manl = (tmpmant[2] >> (denorm - 32))
     143              | ((unsigned long) tmpmant[3] << (48 - denorm));
     144            ld.s.manh = 0;
     145          }
     146        else /* 48 <= denorm < 64 */
     147          {
     148            /* we assume a right shift of 0 is identity */
     149            ld.s.manl = tmpmant[3] >> (denorm - 48);
     150            ld.s.manh = 0;
     151          }
     152  #elif GMP_NUMB_BITS == 8
     153        {
     154          unsigned long long mant = 0;
     155          int i;
     156          for (i = 0; i < 8; i++)
     157            mant |= (unsigned long long) tmpmant[i] << (8*i);
     158          mant >>= denorm;
     159          ld.s.manl = mant;
     160          ld.s.manh = mant >> 32;
     161        }
     162  #else
     163  # error "GMP_NUMB_BITS must be 16, 32 or >= 64"
     164        /* Other values have never been supported anyway. */
     165  #endif
     166        if (MPFR_LIKELY (denorm == 0))
     167          {
     168            ld.s.exph = (e + 0x3FFE) >> 8;
     169            ld.s.expl = (e + 0x3FFE);
     170          }
     171        else
     172          ld.s.exph = ld.s.expl = 0;
     173        ld.s.sign = MPFR_IS_NEG (x);
     174      }
     175  
     176    mpfr_clear (tmp);
     177    MPFR_SAVE_EXPO_FREE (expo);
     178    return ld.ld;
     179  }
     180  
     181  #else
     182  
     183  /* generic code */
     184  long double
     185  mpfr_get_ld (mpfr_srcptr x, mpfr_rnd_t rnd_mode)
     186  {
     187    if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
     188      return (long double) mpfr_get_d (x, rnd_mode);
     189    else /* now x is a normal non-zero number */
     190      {
     191        long double r; /* result */
     192        double s; /* part of result */
     193        MPFR_SAVE_EXPO_DECL (expo);
     194  
     195        MPFR_SAVE_EXPO_MARK (expo);
     196  
     197  #if defined(HAVE_LDOUBLE_MAYBE_DOUBLE_DOUBLE)
     198        if (MPFR_LDBL_MANT_DIG == 106)
     199          {
     200            /* Assume double-double format (as found with the PowerPC ABI).
     201               The generic code below isn't used because numbers with
     202               precision > 106 would not be supported. */
     203            s = mpfr_get_d (x, MPFR_RNDN); /* high part of x */
     204            /* Let's first consider special cases separately. The test for
     205               infinity is really needed to avoid a NaN result. The test
     206               for NaN is mainly for optimization. The test for 0 is useful
     207               to get the correct sign (assuming mpfr_get_d supports signed
     208               zeros on the implementation). */
     209            if (s == 0 || DOUBLE_ISNAN (s) || DOUBLE_ISINF (s))
     210              {
     211                /* we don't propagate the sign bit of NaN */
     212                r = (long double) s;
     213              }
     214            else
     215              {
     216                mpfr_t y, z;
     217  
     218                mpfr_init2 (y, mpfr_get_prec (x));
     219                mpfr_init2 (z, IEEE_DBL_MANT_DIG); /* keep the precision small */
     220                mpfr_set_d (z, s, MPFR_RNDN);  /* exact */
     221                mpfr_sub (y, x, z, MPFR_RNDN); /* exact */
     222                /* Add the second part of y (in the correct rounding mode). */
     223                r = (long double) s + (long double) mpfr_get_d (y, rnd_mode);
     224                mpfr_clear (z);
     225                mpfr_clear (y);
     226              }
     227          }
     228        else
     229  #endif
     230          {
     231            long double m;
     232            mpfr_exp_t sh; /* exponent shift -> x/2^sh is in the double range */
     233            mpfr_t y, z;
     234            int sign;
     235  
     236            /* First round x to the target long double precision, so that
     237               all subsequent operations are exact (this avoids double rounding
     238               problems). However, if the format contains numbers that have
     239               more precision, MPFR won't be able to generate such numbers. */
     240            mpfr_init2 (y, MPFR_LDBL_MANT_DIG);
     241            mpfr_init2 (z, MPFR_LDBL_MANT_DIG);
     242            /* Note about the precision of z: even though IEEE_DBL_MANT_DIG is
     243               sufficient, z has been set to the same precision as y so that
     244               the mpfr_sub below calls mpfr_sub1sp, which is faster than the
     245               generic subtraction, even in this particular case (from tests
     246               done by Patrick Pelissier on a 64-bit Core2 Duo against r7285).
     247               But here there is an important cancellation in the subtraction.
     248               TODO: get more information about what has been tested. */
     249  
     250            mpfr_set (y, x, rnd_mode);
     251            sh = MPFR_GET_EXP (y);
     252            sign = MPFR_SIGN (y);
     253            MPFR_SET_EXP (y, 0);
     254            MPFR_SET_POS (y);
     255  
     256            r = 0.0;
     257            do
     258              {
     259                s = mpfr_get_d (y, MPFR_RNDN); /* high part of y */
     260                r += (long double) s;
     261                mpfr_set_d (z, s, MPFR_RNDN);  /* exact */
     262                mpfr_sub (y, y, z, MPFR_RNDN); /* exact */
     263              }
     264            while (!MPFR_IS_ZERO (y));
     265  
     266            mpfr_clear (z);
     267            mpfr_clear (y);
     268  
     269            /* we now have to multiply back by 2^sh */
     270            MPFR_ASSERTD (r > 0);
     271            if (sh != 0)
     272              {
     273                /* An overflow may occur (example: 0.5*2^1024) */
     274                while (r < 1.0)
     275                  {
     276                    r += r;
     277                    sh--;
     278                  }
     279  
     280                if (sh > 0)
     281                  m = 2.0;
     282                else
     283                  {
     284                    m = 0.5;
     285                    sh = -sh;
     286                  }
     287  
     288                for (;;)
     289                  {
     290                    if (sh % 2)
     291                      r = r * m;
     292                    sh >>= 1;
     293                    if (sh == 0)
     294                      break;
     295                    m = m * m;
     296                  }
     297              }
     298            if (sign < 0)
     299              r = -r;
     300          }
     301        MPFR_SAVE_EXPO_FREE (expo);
     302        return r;
     303      }
     304  }
     305  
     306  #endif
     307  
     308  /* contributed by Damien Stehle */
     309  long double
     310  mpfr_get_ld_2exp (long *expptr, mpfr_srcptr src, mpfr_rnd_t rnd_mode)
     311  {
     312    long double ret;
     313    mpfr_exp_t exp;
     314    mpfr_t tmp;
     315  
     316    if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (src)))
     317      return (long double) mpfr_get_d_2exp (expptr, src, rnd_mode);
     318  
     319    MPFR_ALIAS (tmp, src, MPFR_SIGN (src), 0);
     320    ret = mpfr_get_ld (tmp, rnd_mode);
     321  
     322    exp = MPFR_GET_EXP (src);
     323  
     324    /* rounding can give 1.0, adjust back to 0.5 <= abs(ret) < 1.0 */
     325    if (ret == 1.0)
     326      {
     327        ret = 0.5;
     328        exp ++;
     329      }
     330    else if (ret ==  -1.0)
     331      {
     332        ret = -0.5;
     333        exp ++;
     334      }
     335  
     336    MPFR_ASSERTN ((ret >= 0.5 && ret < 1.0)
     337                  || (ret <= -0.5 && ret > -1.0));
     338    MPFR_ASSERTN (exp >= LONG_MIN && exp <= LONG_MAX);
     339  
     340    *expptr = exp;
     341    return ret;
     342  }