# erf.C

Go to the documentation of this file.
```00001 /*
00002  * Copied from OpenBSD project (src/lib/libm/src/s_erf.c)
00003  * Specialized for 32-bit little endian architectures.
00004  */
00005
00006 /* Real math libraries provide erf(), CUDA also provides an implementation. */
00007 #if defined(WIN32) && !defined(NAMD_CUDA)
00008
00009 /*
00010  * ====================================================
00012  *
00013  * Developed at SunPro, a Sun Microsystems, Inc. business.
00014  * Permission to use, copy, modify, and distribute this
00015  * software is freely granted, provided that this notice
00016  * is preserved.
00017  * ====================================================
00018  */
00019
00020 /* double erf(double x)
00021  * double erfc(double x)
00022  *                           x
00023  *                    2      |\
00024  *     erf(x)  =  ---------  | exp(-t*t)dt
00025  *                 sqrt(pi) \|
00026  *                           0
00027  *
00028  *     erfc(x) =  1-erf(x)
00029  *  Note that
00030  *              erf(-x) = -erf(x)
00031  *              erfc(-x) = 2 - erfc(x)
00032  *
00033  * Method:
00034  *      1. For |x| in [0, 0.84375]
00035  *          erf(x)  = x + x*R(x^2)
00036  *          erfc(x) = 1 - erf(x)           if x in [-.84375,0.25]
00037  *                  = 0.5 + ((0.5-x)-x*R)  if x in [0.25,0.84375]
00038  *         where R = P/Q where P is an odd poly of degree 8 and
00039  *         Q is an odd poly of degree 10.
00040  *                                               -57.90
00041  *                      | R - (erf(x)-x)/x | <= 2
00042  *
00043  *
00044  *         Remark. The formula is derived by noting
00045  *          erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
00046  *         and that
00047  *          2/sqrt(pi) = 1.128379167095512573896158903121545171688
00048  *         is close to one. The interval is chosen because the fix
00049  *         point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
00050  *         near 0.6174), and by some experiment, 0.84375 is chosen to
00051  *         guarantee the error is less than one ulp for erf.
00052  *
00053  *      2. For |x| in [0.84375,1.25], let s = |x| - 1, and
00054  *         c = 0.84506291151 rounded to single (24 bits)
00055  *              erf(x)  = sign(x) * (c  + P1(s)/Q1(s))
00056  *              erfc(x) = (1-c)  - P1(s)/Q1(s) if x > 0
00057  *                        1+(c+P1(s)/Q1(s))    if x < 0
00058  *              |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
00059  *         Remark: here we use the taylor series expansion at x=1.
00060  *              erf(1+s) = erf(1) + s*Poly(s)
00061  *                       = 0.845.. + P1(s)/Q1(s)
00062  *         That is, we use rational approximation to approximate
00063  *                      erf(1+s) - (c = (single)0.84506291151)
00064  *         Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
00065  *         where
00066  *              P1(s) = degree 6 poly in s
00067  *              Q1(s) = degree 6 poly in s
00068  *
00069  *      3. For x in [1.25,1/0.35(~2.857143)],
00070  *              erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
00071  *              erf(x)  = 1 - erfc(x)
00072  *         where
00073  *              R1(z) = degree 7 poly in z, (z=1/x^2)
00074  *              S1(z) = degree 8 poly in z
00075  *
00076  *      4. For x in [1/0.35,28]
00077  *              erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
00078  *                      = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
00079  *                      = 2.0 - tiny            (if x <= -6)
00080  *              erf(x)  = sign(x)*(1.0 - erfc(x)) if x < 6, else
00081  *              erf(x)  = sign(x)*(1.0 - tiny)
00082  *         where
00083  *              R2(z) = degree 6 poly in z, (z=1/x^2)
00084  *              S2(z) = degree 7 poly in z
00085  *
00086  *      Note1:
00087  *         To compute exp(-x*x-0.5625+R/S), let s be a single
00088  *         precision number and s := x; then
00089  *              -x*x = -s*s + (s-x)*(s+x)
00090  *              exp(-x*x-0.5626+R/S) =
00091  *                      exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
00092  *      Note2:
00093  *         Here 4 and 5 make use of the asymptotic series
00094  *                        exp(-x*x)
00095  *              erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
00096  *                        x*sqrt(pi)
00097  *         We use rational approximation to approximate
00098  *              g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
00099  *         Here is the error bound for R1/S1 and R2/S2
00100  *              |R1/S1 - f(x)|  < 2**(-62.57)
00101  *              |R2/S2 - f(x)|  < 2**(-61.52)
00102  *
00103  *      5. For inf > x >= 28
00104  *              erf(x)  = sign(x) *(1 - tiny)  (raise inexact)
00105  *              erfc(x) = tiny*tiny (raise underflow) if x > 0
00106  *                      = 2 - tiny if x<0
00107  *
00108  *      7. Special case:
00109  *              erf(0)  = 0, erf(inf)  = 1, erf(-inf) = -1,
00110  *              erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
00111  *              erfc/erf(NaN) is NaN
00112  */
00113
00114 #include <math.h>
00115
00116 extern "C" {
00117
00118 /*  assume 32 bit int  */
00119
00120 typedef int int32_t;
00121 typedef unsigned int u_int32_t;
00122
00123 /*  assume little endian  */
00124 typedef union
00125 {
00126   double value;
00127   struct
00128   {
00129     u_int32_t lsw;
00130     u_int32_t msw;
00131   } parts;
00132 } ieee_double_shape_type;
00133
00134
00135 /* Get the more significant 32 bit int from a double.  */
00136
00137 #define GET_HIGH_WORD(i,d)                                      \
00138 do {                                                            \
00139   ieee_double_shape_type gh_u;                                  \
00140   gh_u.value = (d);                                             \
00141   (i) = gh_u.parts.msw;                                         \
00142 } while (0)
00143
00144
00145 /* Set the less significant 32 bits of a double from an int.  */
00146
00147 #define SET_LOW_WORD(d,v)                                       \
00148 do {                                                            \
00149   ieee_double_shape_type sl_u;                                  \
00150   sl_u.value = (d);                                             \
00151   sl_u.parts.lsw = (v);                                         \
00152   (d) = sl_u.value;                                             \
00153 } while (0)
00154
00155
00156 /* Eliminate reference to internal OpenBSD call  */
00157
00158 #define __ieee754_exp(X) exp(X)
00159
00160
00161 static const double
00162 tiny        = 1e-300,
00163 half=  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
00164 one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
00165 two =  2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
00166         /* c = (float)0.84506291151 */
00167 erx =  8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
00168 /*
00169  * Coefficients for approximation to  erf on [0,0.84375]
00170  */
00171 efx =  1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */
00172 efx8=  1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
00173 pp0  =  1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
00174 pp1  = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
00175 pp2  = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
00176 pp3  = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
00177 pp4  = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
00178 qq1  =  3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
00179 qq2  =  6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
00180 qq3  =  5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
00181 qq4  =  1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
00182 qq5  = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
00183 /*
00184  * Coefficients for approximation to  erf  in [0.84375,1.25]
00185  */
00186 pa0  = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
00187 pa1  =  4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
00188 pa2  = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
00189 pa3  =  3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
00190 pa4  = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
00191 pa5  =  3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
00192 pa6  = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
00193 qa1  =  1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
00194 qa2  =  5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
00195 qa3  =  7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
00196 qa4  =  1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
00197 qa5  =  1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
00198 qa6  =  1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
00199 /*
00200  * Coefficients for approximation to  erfc in [1.25,1/0.35]
00201  */
00202 ra0  = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
00203 ra1  = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
00204 ra2  = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
00205 ra3  = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
00206 ra4  = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
00207 ra5  = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
00208 ra6  = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
00209 ra7  = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
00210 sa1  =  1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
00211 sa2  =  1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
00212 sa3  =  4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
00213 sa4  =  6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
00214 sa5  =  4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
00215 sa6  =  1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
00216 sa7  =  6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
00217 sa8  = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
00218 /*
00219  * Coefficients for approximation to  erfc in [1/.35,28]
00220  */
00221 rb0  = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
00222 rb1  = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
00223 rb2  = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
00224 rb3  = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
00225 rb4  = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
00226 rb5  = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
00227 rb6  = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
00228 sb1  =  3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
00229 sb2  =  3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
00230 sb3  =  1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
00231 sb4  =  3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
00232 sb5  =  2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
00233 sb6  =  4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
00234 sb7  = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
00235
00236         double erf(double x)
00237 {
00238         int32_t hx,ix,i;
00239         double R,S,P,Q,s,y,z,r;
00240         GET_HIGH_WORD(hx,x);
00241         ix = hx&0x7fffffff;
00242         if(ix>=0x7ff00000) {            /* erf(nan)=nan */
00243             i = ((u_int32_t)hx>>31)<<1;
00244             return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */
00245         }
00246
00247         if(ix < 0x3feb0000) {           /* |x|<0.84375 */
00248             if(ix < 0x3e300000) {       /* |x|<2**-28 */
00249                 if (ix < 0x00800000)
00250                     return 0.125*(8.0*x+efx8*x);  /*avoid underflow */
00251                 return x + efx*x;
00252             }
00253             z = x*x;
00254             r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
00255             s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
00256             y = r/s;
00257             return x + x*y;
00258         }
00259         if(ix < 0x3ff40000) {           /* 0.84375 <= |x| < 1.25 */
00260             s = fabs(x)-one;
00261             P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
00262             Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
00263             if(hx>=0) return erx + P/Q; else return -erx - P/Q;
00264         }
00265         if (ix >= 0x40180000) {         /* inf>|x|>=6 */
00266             if(hx>=0) return one-tiny; else return tiny-one;
00267         }
00268         x = fabs(x);
00269         s = one/(x*x);
00270         if(ix< 0x4006DB6E) {    /* |x| < 1/0.35 */
00271             R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
00272                                 ra5+s*(ra6+s*ra7))))));
00273             S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
00274                                 sa5+s*(sa6+s*(sa7+s*sa8)))))));
00275         } else {        /* |x| >= 1/0.35 */
00276             R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
00277                                 rb5+s*rb6)))));
00278             S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
00279                                 sb5+s*(sb6+s*sb7))))));
00280         }
00281         z  = x;
00282         SET_LOW_WORD(z,0);
00283         r  =  __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S);
00284         if(hx>=0) return one-r/x; else return  r/x-one;
00285 }
00286
00287         double erfc(double x)
00288 {
00289         int32_t hx,ix;
00290         double R,S,P,Q,s,y,z,r;
00291         GET_HIGH_WORD(hx,x);
00292         ix = hx&0x7fffffff;
00293         if(ix>=0x7ff00000) {                    /* erfc(nan)=nan */
00294                                                 /* erfc(+-inf)=0,2 */
00295             return (double)(((u_int32_t)hx>>31)<<1)+one/x;
00296         }
00297
00298         if(ix < 0x3feb0000) {           /* |x|<0.84375 */
00299             if(ix < 0x3c700000)         /* |x|<2**-56 */
00300                 return one-x;
00301             z = x*x;
00302             r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
00303             s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
00304             y = r/s;
00305             if(hx < 0x3fd00000) {       /* x<1/4 */
00306                 return one-(x+x*y);
00307             } else {
00308                 r = x*y;
00309                 r += (x-half);
00310                 return half - r ;
00311             }
00312         }
00313         if(ix < 0x3ff40000) {           /* 0.84375 <= |x| < 1.25 */
00314             s = fabs(x)-one;
00315             P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
00316             Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
00317             if(hx>=0) {
00318                 z  = one-erx; return z - P/Q;
00319             } else {
00320                 z = erx+P/Q; return one+z;
00321             }
00322         }
00323         if (ix < 0x403c0000) {          /* |x|<28 */
00324             x = fabs(x);
00325             s = one/(x*x);
00326             if(ix< 0x4006DB6D) {        /* |x| < 1/.35 ~ 2.857143*/
00327                 R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
00328                                 ra5+s*(ra6+s*ra7))))));
00329                 S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
00330                                 sa5+s*(sa6+s*(sa7+s*sa8)))))));
00331             } else {                    /* |x| >= 1/.35 ~ 2.857143 */
00332                 if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */
00333                 R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
00334                                 rb5+s*rb6)))));
00335                 S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
00336                                 sb5+s*(sb6+s*sb7))))));
00337             }
00338             z  = x;
00339             SET_LOW_WORD(z,0);
00340             r  =  __ieee754_exp(-z*z-0.5625)*
00341                         __ieee754_exp((z-x)*(z+x)+R/S);
00342             if(hx>0) return r/x; else return two-r/x;
00343         } else {
00344             if(hx>0) return tiny*tiny; else return two-tiny;
00345         }
00346 }
00347
00348 }
00349
00350 #else  /* WIN32 */
00351
00352 int dummy_erf(int i) { return i; }  /* avoid empty translation unit */
00353
00354 #endif  /* WIN32 */
00355
```

Generated on Sat May 26 01:17:12 2018 for NAMD by  1.4.7