xref: /netbsd-src/external/lgpl3/mpfr/dist/src/log1p.c (revision ec6772edaf0cdcb5f52a48f4aca5e33a8fb8ecfd)
1d59437c0Smrg /* mpfr_log1p -- Compute log(1+x)
2d59437c0Smrg 
3ba125506Smrg Copyright 2001-2023 Free Software Foundation, Inc.
4efdec83bSmrg Contributed by the AriC and Caramba projects, INRIA.
5d59437c0Smrg 
6d59437c0Smrg This file is part of the GNU MPFR Library.
7d59437c0Smrg 
8d59437c0Smrg The GNU MPFR Library is free software; you can redistribute it and/or modify
9d59437c0Smrg it under the terms of the GNU Lesser General Public License as published by
10d59437c0Smrg the Free Software Foundation; either version 3 of the License, or (at your
11d59437c0Smrg option) any later version.
12d59437c0Smrg 
13d59437c0Smrg The GNU MPFR Library is distributed in the hope that it will be useful, but
14d59437c0Smrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15d59437c0Smrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16d59437c0Smrg License for more details.
17d59437c0Smrg 
18d59437c0Smrg You should have received a copy of the GNU Lesser General Public License
19d59437c0Smrg along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
202ba2404bSmrg https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21d59437c0Smrg 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22d59437c0Smrg 
23d59437c0Smrg #define MPFR_NEED_LONGLONG_H
24d59437c0Smrg #include "mpfr-impl.h"
25d59437c0Smrg 
26299c6f0cSmrg /* Put in y an approximation of log(1+x) for x small.
27ba125506Smrg    We assume |x| < 1/2, in which case:
28ba125506Smrg    |x/2| <= |log(1+x)| <= |2x|.
29299c6f0cSmrg    Return k such that the error is bounded by 2^k*ulp(y).
30299c6f0cSmrg */
31299c6f0cSmrg static int
mpfr_log1p_small(mpfr_ptr y,mpfr_srcptr x)32299c6f0cSmrg mpfr_log1p_small (mpfr_ptr y, mpfr_srcptr x)
33299c6f0cSmrg {
34299c6f0cSmrg   mpfr_prec_t p = MPFR_PREC(y), err;
35299c6f0cSmrg   mpfr_t t, u;
36299c6f0cSmrg   unsigned long i;
37299c6f0cSmrg   int k;
38299c6f0cSmrg 
39ba125506Smrg   MPFR_ASSERTD(MPFR_GET_EXP (x) <= -1); /* ensures |x| < 1/2 */
40299c6f0cSmrg 
41299c6f0cSmrg   /* in the following, theta represents a value with |theta| <= 2^(1-p)
42299c6f0cSmrg      (might be a different value each time) */
43299c6f0cSmrg 
44299c6f0cSmrg   mpfr_init2 (t, p);
45299c6f0cSmrg   mpfr_init2 (u, p);
46299c6f0cSmrg   mpfr_set (t, x, MPFR_RNDF); /* t = x * (1 + theta) */
47299c6f0cSmrg   mpfr_set (y, t, MPFR_RNDF); /* exact */
48299c6f0cSmrg   for (i = 2; ; i++)
49299c6f0cSmrg     {
50299c6f0cSmrg       mpfr_mul (t, t, x, MPFR_RNDF);    /* t = x^i * (1 + theta)^i */
51299c6f0cSmrg       mpfr_div_ui (u, t, i, MPFR_RNDF); /* u = x^i/i * (1 + theta)^(i+1) */
52299c6f0cSmrg       if (MPFR_GET_EXP (u) <= MPFR_GET_EXP (y) - p) /* |u| < ulp(y) */
53299c6f0cSmrg         break;
54299c6f0cSmrg       if (i & 1)
55299c6f0cSmrg         mpfr_add (y, y, u, MPFR_RNDF); /* error <= ulp(y) */
56299c6f0cSmrg       else
57299c6f0cSmrg         mpfr_sub (y, y, u, MPFR_RNDF); /* error <= ulp(y) */
58299c6f0cSmrg     }
59299c6f0cSmrg   /* We assume |(1 + theta)^(i+1)| <= 2.
60299c6f0cSmrg      The neglected part is at most |u| + |u|/2 + ... <= 2|u| < 2 ulp(y)
61299c6f0cSmrg      which has to be multiplied by |(1 + theta)^(i+1)| <= 2, thus at most
62299c6f0cSmrg      4 ulp(y).
63299c6f0cSmrg      The rounding error on y is bounded by:
64299c6f0cSmrg      * for the (i-2) add/sub, each error is bounded by ulp(y),
65299c6f0cSmrg        and since |y| <= |x|, this yields (i-2)*ulp(x)
66299c6f0cSmrg      * from Lemma 3.1 from [Higham02] (see algorithms.tex),
67299c6f0cSmrg        the relative error on u at step i is bounded by:
68299c6f0cSmrg        (i+1)*epsilon/(1-(i+1)*epsilon) where epsilon = 2^(1-p).
69299c6f0cSmrg        If (i+1)*epsilon <= 1/2, then the relative error on u at
70299c6f0cSmrg        step i is bounded by 2*(i+1)*epsilon, and since |u| <= 1/2^(i+1)
71299c6f0cSmrg        at step i, this gives an absolute error bound of;
72299c6f0cSmrg        2*epsilon*x*(3/2^3 + 4/2^4 + 5/2^5 + ...) <= 2*2^(1-p)*x =
73299c6f0cSmrg        4*2^(-p)*x <= 4*ulp(x).
74299c6f0cSmrg 
75299c6f0cSmrg      If (i+1)*epsilon <= 1/2, then the relative error on u at step i
76299c6f0cSmrg      is bounded by (i+1)*epsilon/(1-(i+1)*epsilon) <= 1, thus it follows
77299c6f0cSmrg      |(1 + theta)^(i+1)| <= 2.
78299c6f0cSmrg 
79299c6f0cSmrg      Finally the total error is bounded by 4*ulp(y) + (i-2)*ulp(x) + 4*ulp(x)
80299c6f0cSmrg      = 4*ulp(y) + (i+2)*ulp(x).
81299c6f0cSmrg      Since x/2 <= y, we have ulp(x) <= 2*ulp(y), thus the error is bounded by:
82299c6f0cSmrg      (2*i+8)*ulp(y).
83299c6f0cSmrg   */
84299c6f0cSmrg   err = 2 * i + 8;
85299c6f0cSmrg   k = __gmpfr_int_ceil_log2 (err);
86299c6f0cSmrg   MPFR_ASSERTN(k < p);
87299c6f0cSmrg   /* if k < p, since k = ceil(log2(err)), we have err <= 2^k <= 2^(p-1),
88299c6f0cSmrg      thus i+4 = err/2 <= 2^(p-2), thus (i+4)*epsilon <= 1/2, which implies
89299c6f0cSmrg      our assumption (i+1)*epsilon <= 1/2. */
90299c6f0cSmrg   mpfr_clear (t);
91299c6f0cSmrg   mpfr_clear (u);
92299c6f0cSmrg   return k;
93299c6f0cSmrg }
94299c6f0cSmrg 
95d59437c0Smrg /* The computation of log1p is done by
96299c6f0cSmrg    log1p(x) = log(1+x)
97299c6f0cSmrg    except when x is very small, in which case log1p(x) = x + tiny error,
98299c6f0cSmrg    or when x is small, where we use directly the Taylor expansion.
99299c6f0cSmrg */
100d59437c0Smrg 
101d59437c0Smrg int
mpfr_log1p(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)102d59437c0Smrg mpfr_log1p (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
103d59437c0Smrg {
104d59437c0Smrg   int comp, inexact;
105d59437c0Smrg   mpfr_exp_t ex;
106d59437c0Smrg   MPFR_SAVE_EXPO_DECL (expo);
107d59437c0Smrg 
108d59437c0Smrg   MPFR_LOG_FUNC
109*ec6772edSmrg     (("x[%Pd]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
110*ec6772edSmrg      ("y[%Pd]=%.*Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y,
111d59437c0Smrg       inexact));
112d59437c0Smrg 
113d59437c0Smrg   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
114d59437c0Smrg     {
115d59437c0Smrg       if (MPFR_IS_NAN (x))
116d59437c0Smrg         {
117d59437c0Smrg           MPFR_SET_NAN (y);
118d59437c0Smrg           MPFR_RET_NAN;
119d59437c0Smrg         }
120d59437c0Smrg       /* check for inf or -inf (result is not defined) */
121d59437c0Smrg       else if (MPFR_IS_INF (x))
122d59437c0Smrg         {
123d59437c0Smrg           if (MPFR_IS_POS (x))
124d59437c0Smrg             {
125d59437c0Smrg               MPFR_SET_INF (y);
126d59437c0Smrg               MPFR_SET_POS (y);
127d59437c0Smrg               MPFR_RET (0);
128d59437c0Smrg             }
129d59437c0Smrg           else
130d59437c0Smrg             {
131d59437c0Smrg               MPFR_SET_NAN (y);
132d59437c0Smrg               MPFR_RET_NAN;
133d59437c0Smrg             }
134d59437c0Smrg         }
135d59437c0Smrg       else /* x is zero */
136d59437c0Smrg         {
137d59437c0Smrg           MPFR_ASSERTD (MPFR_IS_ZERO (x));
138d59437c0Smrg           MPFR_SET_ZERO (y);   /* log1p(+/- 0) = +/- 0 */
139d59437c0Smrg           MPFR_SET_SAME_SIGN (y, x);
140d59437c0Smrg           MPFR_RET (0);
141d59437c0Smrg         }
142d59437c0Smrg     }
143d59437c0Smrg 
144d59437c0Smrg   ex = MPFR_GET_EXP (x);
145d59437c0Smrg   if (ex < 0)  /* -0.5 < x < 0.5 */
146d59437c0Smrg     {
147d59437c0Smrg       /* For x > 0,    abs(log(1+x)-x) < x^2/2.
148d59437c0Smrg          For x > -0.5, abs(log(1+x)-x) < x^2. */
149d59437c0Smrg       if (MPFR_IS_POS (x))
150d59437c0Smrg         MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, - ex - 1, 0, 0, rnd_mode, {});
151d59437c0Smrg       else
152d59437c0Smrg         MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, - ex, 0, 1, rnd_mode, {});
153d59437c0Smrg     }
154d59437c0Smrg 
155d59437c0Smrg   comp = mpfr_cmp_si (x, -1);
156d59437c0Smrg   /* log1p(x) is undefined for x < -1 */
157d59437c0Smrg   if (MPFR_UNLIKELY(comp <= 0))
158d59437c0Smrg     {
159d59437c0Smrg       if (comp == 0)
160d59437c0Smrg         /* x=0: log1p(-1)=-inf (divide-by-zero exception) */
161d59437c0Smrg         {
162d59437c0Smrg           MPFR_SET_INF (y);
163d59437c0Smrg           MPFR_SET_NEG (y);
164299c6f0cSmrg           MPFR_SET_DIVBY0 ();
165d59437c0Smrg           MPFR_RET (0);
166d59437c0Smrg         }
167d59437c0Smrg       MPFR_SET_NAN (y);
168d59437c0Smrg       MPFR_RET_NAN;
169d59437c0Smrg     }
170d59437c0Smrg 
171d59437c0Smrg   MPFR_SAVE_EXPO_MARK (expo);
172d59437c0Smrg 
173d59437c0Smrg   /* General case */
174d59437c0Smrg   {
175d59437c0Smrg     /* Declaration of the intermediary variable */
176d59437c0Smrg     mpfr_t t;
177d59437c0Smrg     /* Declaration of the size variable */
178d59437c0Smrg     mpfr_prec_t Ny = MPFR_PREC(y);             /* target precision */
179d59437c0Smrg     mpfr_prec_t Nt;                            /* working precision */
180d59437c0Smrg     mpfr_exp_t err;                            /* error */
181d59437c0Smrg     MPFR_ZIV_DECL (loop);
182d59437c0Smrg 
183d59437c0Smrg     /* compute the precision of intermediary variable */
184d59437c0Smrg     /* the optimal number of bits : see algorithms.tex */
185d59437c0Smrg     Nt = Ny + MPFR_INT_CEIL_LOG2 (Ny) + 6;
186d59437c0Smrg 
187d59437c0Smrg     /* if |x| is smaller than 2^(-e), we will loose about e bits
188d59437c0Smrg        in log(1+x) */
189d59437c0Smrg     if (MPFR_EXP(x) < 0)
190d59437c0Smrg       Nt += -MPFR_EXP(x);
191d59437c0Smrg 
192299c6f0cSmrg     /* initialize of intermediary variable */
193d59437c0Smrg     mpfr_init2 (t, Nt);
194d59437c0Smrg 
195d59437c0Smrg     /* First computation of log1p */
196d59437c0Smrg     MPFR_ZIV_INIT (loop, Nt);
197d59437c0Smrg     for (;;)
198d59437c0Smrg       {
199299c6f0cSmrg         int k;
200299c6f0cSmrg         /* small case: assuming the AGM algorithm used by mpfr_log uses
201299c6f0cSmrg            log2(p) steps for a precision of p bits, we try the special
202299c6f0cSmrg            variant whenever EXP(x) <= -p/log2(p). */
203299c6f0cSmrg         k = 1 + __gmpfr_int_ceil_log2 (Ny); /* the +1 avoids a division by 0
204299c6f0cSmrg                                                when Ny=1 */
205ba125506Smrg         if (MPFR_GET_EXP (x) + 1 <= - (mpfr_exp_t) (Ny / k))
206ba125506Smrg           /* this implies EXP(x) <= -1 thus x < 1/2 */
207299c6f0cSmrg           err = Nt - mpfr_log1p_small (t, x);
208299c6f0cSmrg         else
209299c6f0cSmrg           {
210d59437c0Smrg             /* compute log1p */
211d59437c0Smrg             inexact = mpfr_add_ui (t, x, 1, MPFR_RNDN);      /* 1+x */
212d59437c0Smrg             /* if inexact = 0, then t = x+1, and the result is simply log(t) */
213d59437c0Smrg             if (inexact == 0)
214d59437c0Smrg               {
215d59437c0Smrg                 inexact = mpfr_log (y, t, rnd_mode);
216d59437c0Smrg                 goto end;
217d59437c0Smrg               }
218d59437c0Smrg             mpfr_log (t, t, MPFR_RNDN);        /* log(1+x) */
219d59437c0Smrg 
220299c6f0cSmrg             /* the error is bounded by (1/2+2^(1-EXP(t))*ulp(t)
221299c6f0cSmrg                (cf algorithms.tex)
222d59437c0Smrg                if EXP(t)>=2, then error <= ulp(t)
223d59437c0Smrg                if EXP(t)<=1, then error <= 2^(2-EXP(t))*ulp(t) */
224d59437c0Smrg             err = Nt - MAX (0, 2 - MPFR_GET_EXP (t));
225299c6f0cSmrg           }
226d59437c0Smrg 
227d59437c0Smrg         if (MPFR_LIKELY (MPFR_CAN_ROUND (t, err, Ny, rnd_mode)))
228d59437c0Smrg           break;
229d59437c0Smrg 
230d59437c0Smrg         /* increase the precision */
231d59437c0Smrg         MPFR_ZIV_NEXT (loop, Nt);
232d59437c0Smrg         mpfr_set_prec (t, Nt);
233d59437c0Smrg       }
234d59437c0Smrg     inexact = mpfr_set (y, t, rnd_mode);
235d59437c0Smrg 
236d59437c0Smrg   end:
237d59437c0Smrg     MPFR_ZIV_FREE (loop);
238d59437c0Smrg     mpfr_clear (t);
239d59437c0Smrg   }
240d59437c0Smrg 
241d59437c0Smrg   MPFR_SAVE_EXPO_FREE (expo);
242d59437c0Smrg   return mpfr_check_range (y, inexact, rnd_mode);
243d59437c0Smrg }
244