xref: /netbsd-src/external/lgpl3/mpfr/dist/src/expm1.c (revision ec6772edaf0cdcb5f52a48f4aca5e33a8fb8ecfd)
1 /* mpfr_expm1 -- Compute exp(x)-1
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  /* The computation of expm1 is done by
27     expm1(x)=exp(x)-1
28  */
29 
30 int
mpfr_expm1(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)31 mpfr_expm1 (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
32 {
33   int inexact;
34   mpfr_exp_t ex;
35   MPFR_SAVE_EXPO_DECL (expo);
36 
37   MPFR_LOG_FUNC
38     (("x[%Pd]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
39      ("y[%Pd]=%.*Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y,
40       inexact));
41 
42   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
43     {
44       if (MPFR_IS_NAN (x))
45         {
46           MPFR_SET_NAN (y);
47           MPFR_RET_NAN;
48         }
49       /* check for inf or -inf (expm1(-inf)=-1) */
50       else if (MPFR_IS_INF (x))
51         {
52           if (MPFR_IS_POS (x))
53             {
54               MPFR_SET_INF (y);
55               MPFR_SET_POS (y);
56               MPFR_RET (0);
57             }
58           else
59             return mpfr_set_si (y, -1, rnd_mode);
60         }
61       else
62         {
63           MPFR_ASSERTD (MPFR_IS_ZERO (x));
64           MPFR_SET_ZERO (y);   /* expm1(+/- 0) = +/- 0 */
65           MPFR_SET_SAME_SIGN (y, x);
66           MPFR_RET (0);
67         }
68     }
69 
70   ex = MPFR_GET_EXP (x);
71   if (ex < 0)
72     {
73       /* For -1 < x < 0, abs(expm1(x)-x) < x^2/2.
74          For 0 < x < 1,  abs(expm1(x)-x) < x^2. */
75       if (MPFR_IS_POS (x))
76         MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, - ex, 0, 1, rnd_mode, {});
77       else
78         MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, - ex, 1, 0, rnd_mode, {});
79     }
80 
81   MPFR_SAVE_EXPO_MARK (expo);
82 
83   if (MPFR_IS_NEG (x) && ex > 5)  /* x <= -32 */
84     {
85       mp_limb_t t_limb[(64 - 1) / GMP_NUMB_BITS + 1];
86       mpfr_t t;
87       mpfr_eexp_t err;
88 
89       MPFR_TMP_INIT1(t_limb, t, 64);
90       /* since x < 0, to get an upper bound on x/log(2), we need to divide
91          by an upper bound on log(2) */
92       mpfr_div (t, x, __gmpfr_const_log2_RNDU, MPFR_RNDU); /* > x / ln(2) */
93       err = mpfr_get_exp_t (t, MPFR_RNDU);
94       MPFR_ASSERTD (err < 0);
95       err = err < - MPFR_EXP_MAX ? MPFR_EXP_MAX : - err;
96       /* err = -max(ceil(t),-MPFR_EXP_MAX). */
97       MPFR_LOG_MSG (("err=%" MPFR_EXP_FSPEC "d\n", err));
98       /* exp(x) = 2^(x/ln(2))
99                <= 2^max(-MPFR_EXP_MAX,ceil(x/ln(2)+epsilon))
100          with epsilon > 0 */
101       MPFR_SMALL_INPUT_AFTER_SAVE_EXPO (y, __gmpfr_mone, (mpfr_exp_t) err,
102                                         0, 0, rnd_mode, expo, {});
103     }
104 
105   /* General case */
106   {
107     /* Declaration of the intermediary variable */
108     mpfr_t t;
109     /* Declaration of the size variable */
110     mpfr_prec_t Ny = MPFR_PREC(y);   /* target precision */
111     mpfr_prec_t Nt;                  /* working precision */
112     mpfr_exp_t err, exp_te;          /* error */
113     MPFR_ZIV_DECL (loop);
114 
115     /* compute the precision of intermediary variable */
116     /* the optimal number of bits : see algorithms.tex */
117     Nt = Ny + MPFR_INT_CEIL_LOG2 (Ny) + 6;
118 
119     /* if |x| is smaller than 2^(-e), we will loose about e bits in the
120        subtraction exp(x) - 1 */
121     if (ex < 0)
122       Nt += - ex;
123 
124     /* initialize auxiliary variable */
125     mpfr_init2 (t, Nt);
126 
127     /* First computation of expm1 */
128     MPFR_ZIV_INIT (loop, Nt);
129     for (;;)
130       {
131         MPFR_BLOCK_DECL (flags);
132 
133         /* exp(x) may overflow and underflow */
134         MPFR_BLOCK (flags, mpfr_exp (t, x, MPFR_RNDN));
135 
136         if (MPFR_OVERFLOW (flags)) /* overflow case */
137           {
138             inexact = mpfr_overflow (y, rnd_mode, MPFR_SIGN_POS);
139             MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_OVERFLOW);
140             break;
141           }
142 
143         /* To get an underflow in exp(x), we need exp(x) < 0.5*2^MPFR_EMIN_MIN
144            thus x/log(2) < MPFR_EMIN_MIN-1. But in that case the above
145            MPFR_SMALL_INPUT_AFTER_SAVE_EXPO() will return the result. */
146         MPFR_ASSERTD(!MPFR_UNDERFLOW (flags));
147 
148         exp_te = MPFR_GET_EXP (t);
149         mpfr_sub_ui (t, t, 1, MPFR_RNDN);   /* exp(x)-1 */
150 
151         /* error estimate */
152         /*err=Nt-(__gmpfr_ceil_log2(1+pow(2,MPFR_EXP(te)-MPFR_EXP(t))));*/
153         err = Nt - (MAX (exp_te - MPFR_GET_EXP (t), 0) + 1);
154 
155         if (MPFR_LIKELY (MPFR_CAN_ROUND (t, err, Ny, rnd_mode)))
156           {
157             inexact = mpfr_set (y, t, rnd_mode);
158             break;
159           }
160 
161         /* increase the precision */
162         MPFR_ZIV_NEXT (loop, Nt);
163         mpfr_set_prec (t, Nt);
164       }
165     MPFR_ZIV_FREE (loop);
166 
167     mpfr_clear (t);
168   }
169 
170   MPFR_SAVE_EXPO_FREE (expo);
171   return mpfr_check_range (y, inexact, rnd_mode);
172 }
173