Home | History | Annotate | Line # | Download | only in src
      1 /* mpfr_exp2 -- power of 2 function 2^y
      2 
      3 Copyright 2001-2023 Free Software Foundation, Inc.
      4 Contributed by the AriC and Caramba projects, INRIA.
      5 
      6 This file is part of the GNU MPFR Library.
      7 
      8 The GNU MPFR Library is free software; you can redistribute it and/or modify
      9 it under the terms of the GNU Lesser General Public License as published by
     10 the Free Software Foundation; either version 3 of the License, or (at your
     11 option) any later version.
     12 
     13 The GNU MPFR Library is distributed in the hope that it will be useful, but
     14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
     16 License for more details.
     17 
     18 You should have received a copy of the GNU Lesser General Public License
     19 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
     20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
     21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
     22 
     23 #define MPFR_NEED_LONGLONG_H
     24 #include "mpfr-impl.h"
     25 
     26 /* TODO: mpfr_get_exp_t is called 3 times, with 3 different directed
     27    rounding modes. One could reduce it to only one call thanks to the
     28    inexact flag, but is it worth? */
     29 
     30 /* Convert x to an mpfr_eexp_t integer, with saturation at the minimum
     31    and maximum values. Flags are unchanged. */
     32 static mpfr_eexp_t
     33 round_to_eexp_t (mpfr_srcptr x, mpfr_rnd_t rnd_mode)
     34 {
     35   mpfr_flags_t flags = __gmpfr_flags;
     36   mpfr_eexp_t e;
     37 
     38   e = mpfr_get_exp_t (x, rnd_mode);
     39   __gmpfr_flags = flags;
     40   return e;
     41 }
     42 
     43 /* The computation of y = 2^z is done by                           *
     44  *     y = exp(z*log(2)). The result is exact iff z is an integer. */
     45 
     46 int
     47 mpfr_exp2 (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
     48 {
     49   int inexact;
     50   mpfr_eexp_t xint;  /* note: will fit in mpfr_exp_t */
     51   mpfr_t xfrac;
     52   MPFR_SAVE_EXPO_DECL (expo);
     53 
     54   MPFR_LOG_FUNC
     55     (("x[%Pd]=%.*Rg rnd=%d", mpfr_get_prec(x), mpfr_log_prec, x, rnd_mode),
     56      ("y[%Pd]=%.*Rg inexact=%d", mpfr_get_prec(y), mpfr_log_prec, y,
     57       inexact));
     58 
     59   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
     60     {
     61       if (MPFR_IS_NAN (x))
     62         {
     63           MPFR_SET_NAN (y);
     64           MPFR_RET_NAN;
     65         }
     66       else if (MPFR_IS_INF (x))
     67         {
     68           if (MPFR_IS_POS (x))
     69             MPFR_SET_INF (y);
     70           else
     71             MPFR_SET_ZERO (y);
     72           MPFR_SET_POS (y);
     73           MPFR_RET (0);
     74         }
     75       else /* 2^0 = 1 */
     76         {
     77           MPFR_ASSERTD (MPFR_IS_ZERO(x));
     78           return mpfr_set_ui (y, 1, rnd_mode);
     79         }
     80     }
     81 
     82   /* Since the smallest representable non-zero float is 1/2 * 2^emin,
     83      if x <= emin - 2, the result is either 1/2 * 2^emin or 0.
     84      Warning, for emin - 2 < x < emin - 1, we cannot conclude, since 2^x
     85      might round to 2^(emin - 1) for rounding away or to nearest, and there
     86      might be no underflow, since we consider underflow "after rounding". */
     87 
     88   if (MPFR_UNLIKELY (round_to_eexp_t (x, MPFR_RNDU) <= __gmpfr_emin - 2))
     89     return mpfr_underflow (y, rnd_mode == MPFR_RNDN ? MPFR_RNDZ : rnd_mode, 1);
     90 
     91   if (MPFR_UNLIKELY (round_to_eexp_t (x, MPFR_RNDD) >= __gmpfr_emax))
     92     return mpfr_overflow (y, rnd_mode, 1);
     93 
     94   /* We now know that emin - 2 < x < emax. Note that an underflow or
     95      overflow is still possible (we have eliminated only easy cases). */
     96 
     97   MPFR_SAVE_EXPO_MARK (expo);
     98 
     99   /* 2^x = 1 + x*log(2) + O(x^2) for x near zero, and for |x| <= 1 we have
    100      |2^x - 1| <= x < 2^EXP(x). If x > 0 we must round away from 0 (dir=1);
    101      if x < 0 we must round toward 0 (dir=0). */
    102   MPFR_SMALL_INPUT_AFTER_SAVE_EXPO (y, __gmpfr_one, - MPFR_GET_EXP (x), 0,
    103                                     MPFR_IS_POS (x), rnd_mode, expo, {});
    104 
    105   xint = mpfr_get_exp_t (x, MPFR_RNDZ);
    106   MPFR_ASSERTD (__gmpfr_emin - 2 < xint && xint < __gmpfr_emax);
    107 
    108   mpfr_init2 (xfrac, MPFR_PREC (x));
    109   MPFR_DBGRES (inexact = mpfr_frac (xfrac, x, MPFR_RNDN));
    110   MPFR_ASSERTD (inexact == 0);
    111 
    112   if (MPFR_IS_ZERO (xfrac))
    113     {
    114       /* Here, emin - 1 <= x <= emax - 1, so that an underflow or overflow
    115          will not be possible. */
    116       mpfr_set_ui (y, 1, MPFR_RNDN);
    117       inexact = 0;
    118     }
    119   else
    120     {
    121       /* Declaration of the intermediary variable */
    122       mpfr_t t;
    123 
    124       /* Declaration of the size variable */
    125       mpfr_prec_t Ny = MPFR_PREC(y);              /* target precision */
    126       mpfr_prec_t Nt;                             /* working precision */
    127       mpfr_exp_t err;                             /* error */
    128       MPFR_ZIV_DECL (loop);
    129 
    130       /* compute the precision of intermediary variable */
    131       /* the optimal number of bits : see algorithms.tex */
    132       Nt = Ny + 5 + MPFR_INT_CEIL_LOG2 (Ny);
    133 
    134       /* initialize of intermediary variable */
    135       mpfr_init2 (t, Nt);
    136 
    137       /* First computation */
    138       MPFR_ZIV_INIT (loop, Nt);
    139       for (;;)
    140         {
    141           /* compute exp(x*ln(2))*/
    142           mpfr_const_log2 (t, MPFR_RNDU);       /* ln(2) */
    143           mpfr_mul (t, xfrac, t, MPFR_RNDU);    /* xfrac * ln(2) */
    144           err = Nt - (MPFR_GET_EXP (t) + 2);   /* Estimate of the error */
    145           mpfr_exp (t, t, MPFR_RNDN);           /* exp(xfrac * ln(2)) */
    146 
    147           if (MPFR_LIKELY (MPFR_CAN_ROUND (t, err, Ny, rnd_mode)))
    148             break;
    149 
    150           /* Actualisation of the precision */
    151           MPFR_ZIV_NEXT (loop, Nt);
    152           mpfr_set_prec (t, Nt);
    153         }
    154       MPFR_ZIV_FREE (loop);
    155 
    156       inexact = mpfr_set (y, t, rnd_mode);
    157 
    158       mpfr_clear (t);
    159     }
    160 
    161   mpfr_clear (xfrac);
    162 
    163   if (MPFR_UNLIKELY (rnd_mode == MPFR_RNDN && xint == __gmpfr_emin - 1 &&
    164                      MPFR_GET_EXP (y) == 0 && mpfr_powerof2_raw (y)))
    165     {
    166       /* y was rounded down to 1/2 and the rounded value with an unbounded
    167          exponent range would be 2^(emin-2), i.e. the midpoint between 0
    168          and the smallest positive FP number. This is a double rounding
    169          problem: we should not round to 0, but to (1/2) * 2^emin. */
    170       MPFR_SET_EXP (y, __gmpfr_emin);
    171       inexact = 1;
    172       MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_UNDERFLOW);
    173     }
    174   else
    175     {
    176       /* The following is OK due to early overflow/underflow checking.
    177          the exponent may be slightly out-of-range, but this will be
    178          handled by mpfr_check_range. */
    179       MPFR_EXP (y) += xint;
    180     }
    181 
    182   MPFR_SAVE_EXPO_FREE (expo);
    183   return mpfr_check_range (y, inexact, rnd_mode);
    184 }
    185