xref: /netbsd-src/external/lgpl3/mpfr/dist/src/exp.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
1 /* mpfr_exp -- exponential of a floating-point number
2 
3 Copyright 1999-2018 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 http://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[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
45      ("y[%Pu]=%.*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 }
188