xref: /netbsd-src/external/lgpl3/mpfr/dist/src/erf.c (revision e6c7e151de239c49d2e38720a061ed9d1fa99309)
1 /* mpfr_erf -- error function of a floating-point number
2 
3 Copyright 2001, 2003-2018 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 http://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
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_mul (l, x, 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
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
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   double tauk;
190   mpfr_t y, s, t, u;
191   unsigned int k;
192   int log2tauk;
193   int inex;
194   MPFR_GROUP_DECL (group);
195   MPFR_ZIV_DECL (loop);
196 
197   n = MPFR_PREC (res); /* target precision */
198 
199   /* initial working precision */
200   m = n + (mpfr_prec_t) (xf2 / LOG2) + 8 + MPFR_INT_CEIL_LOG2 (n);
201 
202   MPFR_GROUP_INIT_4(group, m, y, s, t, u);
203 
204   MPFR_ZIV_INIT (loop, m);
205   for (;;)
206     {
207       mpfr_mul (y, x, x, MPFR_RNDU); /* err <= 1 ulp */
208       mpfr_set_ui (s, 1, MPFR_RNDN);
209       mpfr_set_ui (t, 1, MPFR_RNDN);
210       tauk = 0.0;
211 
212       for (k = 1; ; k++)
213         {
214           mpfr_mul (t, y, t, MPFR_RNDU);
215           mpfr_div_ui (t, t, k, MPFR_RNDU);
216           mpfr_div_ui (u, t, 2 * k + 1, MPFR_RNDU);
217           sigmak = MPFR_GET_EXP (s);
218           if (k % 2)
219             mpfr_sub (s, s, u, MPFR_RNDN);
220           else
221             mpfr_add (s, s, u, MPFR_RNDN);
222           sigmak -= MPFR_GET_EXP(s);
223           nuk = MPFR_GET_EXP(u) - MPFR_GET_EXP(s);
224 
225           if ((nuk < - (mpfr_exp_t) m) && ((double) k >= xf2))
226             break;
227 
228           /* tauk <- 1/2 + tauk * 2^sigmak + (1+8k)*2^nuk */
229           tauk = 0.5 + mul_2exp (tauk, sigmak)
230             + mul_2exp (1.0 + 8.0 * (double) k, nuk);
231         }
232 
233       mpfr_mul (s, x, s, MPFR_RNDU);
234       MPFR_SET_EXP (s, MPFR_GET_EXP (s) + 1);
235 
236       mpfr_const_pi (t, MPFR_RNDZ);
237       mpfr_sqrt (t, t, MPFR_RNDZ);
238       mpfr_div (s, s, t, MPFR_RNDN);
239       tauk = 4.0 * tauk + 11.0; /* final ulp-error on s */
240       log2tauk = __gmpfr_ceil_log2 (tauk);
241 
242       if (MPFR_LIKELY (MPFR_CAN_ROUND (s, m - log2tauk, n, rnd_mode)))
243         break;
244 
245       /* Actualisation of the precision */
246       MPFR_ZIV_NEXT (loop, m);
247       MPFR_GROUP_REPREC_4 (group, m, y, s, t, u);
248     }
249   MPFR_ZIV_FREE (loop);
250 
251   inex = mpfr_set (res, s, rnd_mode);
252 
253   MPFR_GROUP_CLEAR (group);
254 
255   return inex;
256 }
257