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