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