1 /* mpfr_erf -- error function of a floating-point number
2
3 Copyright 2001, 2003-2020 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 static int mpfr_erf_0 (mpfr_ptr, mpfr_srcptr, double, mpfr_rnd_t);
27
28 int
mpfr_erf(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)29 mpfr_erf (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
30 {
31 mpfr_t xf;
32 mp_limb_t xf_limb[(53 - 1) / GMP_NUMB_BITS + 1];
33 int inex, large;
34 MPFR_SAVE_EXPO_DECL (expo);
35
36 MPFR_LOG_FUNC
37 (("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
38 ("y[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y, inex));
39
40 if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
41 {
42 if (MPFR_IS_NAN (x))
43 {
44 MPFR_SET_NAN (y);
45 MPFR_RET_NAN;
46 }
47 else if (MPFR_IS_INF (x)) /* erf(+inf) = +1, erf(-inf) = -1 */
48 return mpfr_set_si (y, MPFR_INT_SIGN (x), MPFR_RNDN);
49 else /* erf(+0) = +0, erf(-0) = -0 */
50 {
51 MPFR_ASSERTD (MPFR_IS_ZERO (x));
52 return mpfr_set (y, x, MPFR_RNDN); /* should keep the sign of x */
53 }
54 }
55
56 /* now x is neither NaN, Inf nor 0 */
57
58 /* first try expansion at x=0 when x is small, or asymptotic expansion
59 where x is large */
60
61 MPFR_SAVE_EXPO_MARK (expo);
62
63 /* around x=0, we have erf(x) = 2x/sqrt(Pi) (1 - x^2/3 + ...),
64 with 1 - x^2/3 <= sqrt(Pi)*erf(x)/2/x <= 1 for x >= 0. This means that
65 if x^2/3 < 2^(-PREC(y)-1) we can decide of the correct rounding,
66 unless we have a worst-case for 2x/sqrt(Pi). */
67 if (MPFR_EXP(x) < - (mpfr_exp_t) (MPFR_PREC(y) / 2))
68 {
69 /* we use 2x/sqrt(Pi) (1 - x^2/3) <= erf(x) <= 2x/sqrt(Pi) for x > 0
70 and 2x/sqrt(Pi) <= erf(x) <= 2x/sqrt(Pi) (1 - x^2/3) for x < 0.
71 In both cases |2x/sqrt(Pi) (1 - x^2/3)| <= |erf(x)| <= |2x/sqrt(Pi)|.
72 We will compute l and h such that l <= |2x/sqrt(Pi) (1 - x^2/3)|
73 and |2x/sqrt(Pi)| <= h. If l and h round to the same value to
74 precision PREC(y) and rounding rnd_mode, then we are done. */
75 mpfr_t l, h; /* lower and upper bounds for erf(x) */
76 int ok, inex2;
77
78 mpfr_init2 (l, MPFR_PREC(y) + 17);
79 mpfr_init2 (h, MPFR_PREC(y) + 17);
80 /* first compute l */
81 mpfr_sqr (l, x, MPFR_RNDU);
82 mpfr_div_ui (l, l, 3, MPFR_RNDU); /* upper bound on x^2/3 */
83 mpfr_ui_sub (l, 1, l, MPFR_RNDZ); /* lower bound on 1 - x^2/3 */
84 mpfr_const_pi (h, MPFR_RNDU); /* upper bound of Pi */
85 mpfr_sqrt (h, h, MPFR_RNDU); /* upper bound on sqrt(Pi) */
86 mpfr_div (l, l, h, MPFR_RNDZ); /* lower bound on 1/sqrt(Pi) (1 - x^2/3) */
87 mpfr_mul_2ui (l, l, 1, MPFR_RNDZ); /* 2/sqrt(Pi) (1 - x^2/3) */
88 mpfr_mul (l, l, x, MPFR_RNDZ); /* |l| is a lower bound on
89 |2x/sqrt(Pi) (1 - x^2/3)| */
90 /* now compute h */
91 mpfr_const_pi (h, MPFR_RNDD); /* lower bound on Pi */
92 mpfr_sqrt (h, h, MPFR_RNDD); /* lower bound on sqrt(Pi) */
93 mpfr_div_2ui (h, h, 1, MPFR_RNDD); /* lower bound on sqrt(Pi)/2 */
94 /* since sqrt(Pi)/2 < 1, the following should not underflow */
95 mpfr_div (h, x, h, MPFR_IS_POS(x) ? MPFR_RNDU : MPFR_RNDD);
96 /* round l and h to precision PREC(y) */
97 inex = mpfr_prec_round (l, MPFR_PREC(y), rnd_mode);
98 inex2 = mpfr_prec_round (h, MPFR_PREC(y), rnd_mode);
99 /* Caution: we also need inex=inex2 (inex might be 0). */
100 ok = SAME_SIGN (inex, inex2) && mpfr_cmp (l, h) == 0;
101 if (ok)
102 mpfr_set (y, h, rnd_mode);
103 mpfr_clear (l);
104 mpfr_clear (h);
105 if (ok)
106 goto end;
107 /* this test can still fail for small precision, for example
108 for x=-0.100E-2 with a target precision of 3 bits, since
109 the error term x^2/3 is not that small. */
110 }
111
112 MPFR_TMP_INIT1(xf_limb, xf, 53);
113 mpfr_div (xf, x, __gmpfr_const_log2_RNDU, MPFR_RNDZ); /* round to zero
114 ensures we get a lower bound of |x/log(2)| */
115 mpfr_mul (xf, xf, x, MPFR_RNDZ);
116 large = mpfr_cmp_ui (xf, MPFR_PREC (y) + 1) > 0;
117
118 /* when x goes to infinity, we have erf(x) = 1 - 1/sqrt(Pi)/exp(x^2)/x + ...
119 and |erf(x) - 1| <= exp(-x^2) is true for any x >= 0, thus if
120 exp(-x^2) < 2^(-PREC(y)-1) the result is 1 or 1-epsilon.
121 This rewrites as x^2/log(2) > p+1. */
122 if (MPFR_UNLIKELY (large))
123 /* |erf x| = 1 or 1- */
124 {
125 mpfr_rnd_t rnd2 = MPFR_IS_POS (x) ? rnd_mode : MPFR_INVERT_RND(rnd_mode);
126 if (rnd2 == MPFR_RNDN || rnd2 == MPFR_RNDU || rnd2 == MPFR_RNDA)
127 {
128 inex = MPFR_INT_SIGN (x);
129 mpfr_set_si (y, inex, rnd2);
130 }
131 else /* round to zero */
132 {
133 inex = -MPFR_INT_SIGN (x);
134 mpfr_setmax (y, 0); /* warning: setmax keeps the old sign of y */
135 MPFR_SET_SAME_SIGN (y, x);
136 }
137 }
138 else /* use Taylor */
139 {
140 double xf2;
141
142 /* FIXME: get rid of doubles/mpfr_get_d here */
143 xf2 = mpfr_get_d (x, MPFR_RNDN);
144 xf2 = xf2 * xf2; /* xf2 ~ x^2 */
145 inex = mpfr_erf_0 (y, x, xf2, rnd_mode);
146 }
147
148 end:
149 MPFR_SAVE_EXPO_FREE (expo);
150 return mpfr_check_range (y, inex, rnd_mode);
151 }
152
153 /* return x*2^e */
154 static double
mul_2exp(double x,mpfr_exp_t e)155 mul_2exp (double x, mpfr_exp_t e)
156 {
157 /* Most of the times, the argument is negative */
158 if (MPFR_UNLIKELY (e > 0))
159 {
160 while (e--)
161 x *= 2.0;
162 }
163 else
164 {
165 while (e <= -16)
166 {
167 x *= (1.0 / 65536.0);
168 e += 16;
169 }
170 while (e++)
171 x *= 0.5;
172 }
173
174 return x;
175 }
176
177 /* evaluates erf(x) using the expansion at x=0:
178
179 erf(x) = 2/sqrt(Pi) * sum((-1)^k*x^(2k+1)/k!/(2k+1), k=0..infinity)
180
181 Assumes x is neither NaN nor infinite nor zero.
182 Assumes also that e*x^2 <= n (target precision).
183 */
184 static int
mpfr_erf_0(mpfr_ptr res,mpfr_srcptr x,double xf2,mpfr_rnd_t rnd_mode)185 mpfr_erf_0 (mpfr_ptr res, mpfr_srcptr x, double xf2, mpfr_rnd_t rnd_mode)
186 {
187 mpfr_prec_t n, m;
188 mpfr_exp_t nuk, sigmak;
189 mpfr_t y, s, t, u;
190 unsigned int k;
191 int inex;
192 MPFR_GROUP_DECL (group);
193 MPFR_ZIV_DECL (loop);
194
195 n = MPFR_PREC (res); /* target precision */
196
197 /* initial working precision */
198 m = n + (mpfr_prec_t) (xf2 / LOG2) + 8 + MPFR_INT_CEIL_LOG2 (n);
199
200 MPFR_GROUP_INIT_4(group, m, y, s, t, u);
201
202 MPFR_ZIV_INIT (loop, m);
203 for (;;)
204 {
205 mpfr_t tauk;
206 mpfr_exp_t log2tauk;
207
208 mpfr_sqr (y, x, MPFR_RNDU); /* err <= 1 ulp */
209 mpfr_set_ui (s, 1, MPFR_RNDN);
210 mpfr_set_ui (t, 1, MPFR_RNDN);
211 mpfr_init2 (tauk, 53);
212 mpfr_set_ui (tauk, 0, MPFR_RNDU);
213
214 for (k = 1; ; k++)
215 {
216 mpfr_mul (t, y, t, MPFR_RNDU);
217 mpfr_div_ui (t, t, k, MPFR_RNDU);
218 mpfr_div_ui (u, t, 2 * k + 1, MPFR_RNDU);
219 sigmak = MPFR_GET_EXP (s);
220 if (k % 2)
221 mpfr_sub (s, s, u, MPFR_RNDN);
222 else
223 mpfr_add (s, s, u, MPFR_RNDN);
224 sigmak -= MPFR_GET_EXP(s);
225 nuk = MPFR_GET_EXP(u) - MPFR_GET_EXP(s);
226
227 if ((nuk < - (mpfr_exp_t) m) && (k >= xf2))
228 break;
229
230 /* tauk <- 1/2 + tauk * 2^sigmak + (1+8k)*2^nuk */
231 mpfr_mul_2si (tauk, tauk, sigmak, MPFR_RNDU);
232 mpfr_add_d (tauk, tauk, 0.5 + mul_2exp (1.0 + 8.0 * (double) k, nuk),
233 MPFR_RNDU);
234 }
235
236 mpfr_mul (s, x, s, MPFR_RNDU);
237 MPFR_SET_EXP (s, MPFR_GET_EXP (s) + 1);
238
239 mpfr_const_pi (t, MPFR_RNDZ);
240 mpfr_sqrt (t, t, MPFR_RNDZ);
241 mpfr_div (s, s, t, MPFR_RNDN);
242 /* tauk = 4 * tauk + 11: final ulp-error on s */
243 mpfr_mul_2ui (tauk, tauk, 2, MPFR_RNDU);
244 mpfr_add_ui (tauk, tauk, 11, MPFR_RNDU);
245 /* In practice, one should not get an infinity, as it would require
246 a huge precision and a lot of time, but just in case... */
247 MPFR_ASSERTN (!MPFR_IS_INF (tauk));
248 log2tauk = MPFR_GET_EXP (tauk);
249 mpfr_clear (tauk);
250
251 if (MPFR_LIKELY (MPFR_CAN_ROUND (s, m - log2tauk, n, rnd_mode)))
252 break;
253
254 /* Actualisation of the precision */
255 MPFR_ZIV_NEXT (loop, m);
256 MPFR_GROUP_REPREC_4 (group, m, y, s, t, u);
257 }
258 MPFR_ZIV_FREE (loop);
259
260 inex = mpfr_set (res, s, rnd_mode);
261
262 MPFR_GROUP_CLEAR (group);
263
264 return inex;
265 }
266