(root)/
mpfr-4.2.1/
src/
exp.c
       1  /* mpfr_exp -- exponential of a floating-point number
       2  
       3  Copyright 1999-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  #include "mpfr-impl.h"
      24  
      25  /* Cache for emin and emax bounds.
      26     Contrary to other caches, it uses a fixed size for the mantissa,
      27     so there is no dynamic allocation, and no need to free them. */
      28  static MPFR_THREAD_ATTR mpfr_exp_t previous_emin;
      29  static MPFR_THREAD_ATTR mp_limb_t  bound_emin_limb[(32 - 1) / GMP_NUMB_BITS + 1];
      30  static MPFR_THREAD_ATTR mpfr_t     bound_emin;
      31  static MPFR_THREAD_ATTR mpfr_exp_t previous_emax;
      32  static MPFR_THREAD_ATTR mp_limb_t  bound_emax_limb[(32 - 1) / GMP_NUMB_BITS + 1];
      33  static MPFR_THREAD_ATTR mpfr_t     bound_emax;
      34  
      35  int
      36  mpfr_exp (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
      37  {
      38    mpfr_exp_t expx;
      39    mpfr_prec_t precy;
      40    int inexact;
      41    MPFR_SAVE_EXPO_DECL (expo);
      42  
      43    MPFR_LOG_FUNC
      44      (("x[%Pd]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
      45       ("y[%Pd]=%.*Rg inexact=%d",
      46        mpfr_get_prec (y), mpfr_log_prec, y, inexact));
      47  
      48    if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(x) ))
      49      {
      50        if (MPFR_IS_NAN(x))
      51          {
      52            MPFR_SET_NAN(y);
      53            MPFR_RET_NAN;
      54          }
      55        else if (MPFR_IS_INF(x))
      56          {
      57            if (MPFR_IS_POS(x))
      58              MPFR_SET_INF(y);
      59            else
      60              MPFR_SET_ZERO(y);
      61            MPFR_SET_POS(y);
      62            MPFR_RET(0);
      63          }
      64        else
      65          {
      66            MPFR_ASSERTD(MPFR_IS_ZERO(x));
      67            return mpfr_set_ui (y, 1, rnd_mode);
      68          }
      69      }
      70  
      71    /* First, let's detect most overflow and underflow cases. */
      72    /* emax bound is cached. Check if the value in cache is ok */
      73    if (MPFR_UNLIKELY (mpfr_get_emax() != previous_emax))
      74      {
      75        /* Recompute the emax bound */
      76        mp_limb_t e_limb[MPFR_EXP_LIMB_SIZE];
      77        mpfr_t e;
      78  
      79        /* We extend the exponent range and save the flags. */
      80        MPFR_SAVE_EXPO_MARK (expo);
      81  
      82        MPFR_TMP_INIT1(e_limb, e, sizeof (mpfr_exp_t) * CHAR_BIT);
      83        MPFR_TMP_INIT1(bound_emax_limb, bound_emax, 32);
      84  
      85        inexact = mpfr_set_exp_t (e, expo.saved_emax, MPFR_RNDN);
      86        MPFR_ASSERTD (inexact == 0);
      87        mpfr_mul (bound_emax, expo.saved_emax < 0 ?
      88                  __gmpfr_const_log2_RNDD : __gmpfr_const_log2_RNDU,
      89                  e, MPFR_RNDU);
      90        previous_emax = expo.saved_emax;
      91        MPFR_SAVE_EXPO_FREE (expo);
      92      }
      93  
      94    /* mpfr_cmp works even in reduced emin,emax range */
      95    if (MPFR_UNLIKELY (mpfr_cmp (x, bound_emax) >= 0))
      96      {
      97        /* x > log(2^emax), thus exp(x) > 2^emax */
      98        return mpfr_overflow (y, rnd_mode, 1);
      99      }
     100  
     101    /* emin bound is cached. Check if the value in cache is ok */
     102    if (MPFR_UNLIKELY (mpfr_get_emin() != previous_emin))
     103      {
     104        mp_limb_t e_limb[MPFR_EXP_LIMB_SIZE];
     105        mpfr_t e;
     106  
     107        /* We extend the exponent range and save the flags. */
     108        MPFR_SAVE_EXPO_MARK (expo);
     109  
     110        /* avoid using a full limb since arithmetic might be slower */
     111        MPFR_TMP_INIT1(e_limb, e, sizeof (mpfr_exp_t) * CHAR_BIT - 1);
     112        MPFR_TMP_INIT1(bound_emin_limb, bound_emin, 32);
     113  
     114        inexact = mpfr_set_exp_t (e, expo.saved_emin, MPFR_RNDN);
     115        MPFR_ASSERTD (inexact == 0);
     116        inexact = mpfr_sub_ui (e, e, 2, MPFR_RNDN);
     117        MPFR_ASSERTD (inexact == 0);
     118        mpfr_const_log2 (bound_emin, expo.saved_emin < 0 ? MPFR_RNDU : MPFR_RNDD);
     119        mpfr_mul (bound_emin, bound_emin, e, MPFR_RNDD);
     120        previous_emin = expo.saved_emin;
     121        MPFR_SAVE_EXPO_FREE (expo);
     122      }
     123  
     124    if (MPFR_UNLIKELY (mpfr_cmp (x, bound_emin) <= 0))
     125      {
     126        /* x < log(2^(emin - 2)), thus exp(x) < 2^(emin - 2) */
     127        return mpfr_underflow (y, rnd_mode == MPFR_RNDN ? MPFR_RNDZ : rnd_mode,
     128                               1);
     129      }
     130  
     131    expx  = MPFR_GET_EXP (x);
     132    precy = MPFR_PREC (y);
     133  
     134    /* if x < 2^(-precy), then exp(x) gives 1 +/- 1 ulp(1) */
     135    if (MPFR_UNLIKELY (expx < 0 && (mpfr_uexp_t) (-expx) > precy))
     136      {
     137        mpfr_exp_t emin = __gmpfr_emin;
     138        mpfr_exp_t emax = __gmpfr_emax;
     139        int signx = MPFR_SIGN (x);
     140  
     141        /* Make sure that the exponent range is large enough:
     142         * [0,2] is sufficient in all precisions.
     143         */
     144        __gmpfr_emin = 0;
     145        __gmpfr_emax = 2;
     146  
     147        MPFR_SET_POS (y);
     148        if (MPFR_IS_NEG_SIGN (signx) && (rnd_mode == MPFR_RNDD ||
     149                                         rnd_mode == MPFR_RNDZ))
     150          {
     151            mpfr_setmax (y, 0);  /* y = 1 - epsilon */
     152            inexact = -1;
     153          }
     154        else
     155          {
     156            mpfr_setmin (y, 1);  /* y = 1 */
     157            if (MPFR_IS_POS_SIGN (signx) && (rnd_mode == MPFR_RNDU ||
     158                                             rnd_mode == MPFR_RNDA))
     159              {
     160                /* Warning: should work for precision 1 bit too! */
     161                mpfr_nextabove (y);
     162                inexact = 1;
     163              }
     164            else
     165              inexact = -MPFR_FROM_SIGN_TO_INT(signx);
     166          }
     167  
     168        __gmpfr_emin = emin;
     169        __gmpfr_emax = emax;
     170      }
     171    else  /* General case */
     172      {
     173        if (MPFR_UNLIKELY (precy >= MPFR_EXP_THRESHOLD))
     174          /* mpfr_exp_3 saves the exponent range and flags itself, otherwise
     175             the flag changes in mpfr_exp_3 are lost */
     176          inexact = mpfr_exp_3 (y, x, rnd_mode); /* O(M(n) log(n)^2) */
     177        else
     178          {
     179            MPFR_SAVE_EXPO_MARK (expo);
     180            inexact = mpfr_exp_2 (y, x, rnd_mode); /* O(n^(1/3) M(n)) */
     181            MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, __gmpfr_flags);
     182            MPFR_SAVE_EXPO_FREE (expo);
     183          }
     184      }
     185  
     186    return mpfr_check_range (y, inexact, rnd_mode);
     187  }