(root)/
mpfr-4.2.1/
src/
erf.c
       1  /* mpfr_erf -- error function of a floating-point number
       2  
       3  Copyright 2001, 2003-2023 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
      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[%Pd]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
      38       ("y[%Pd]=%.*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_equal_p (l, h);
     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    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  }