148402Sbostic /*- 256950Sbostic * Copyright (c) 1992 The Regents of the University of California. 348402Sbostic * All rights reserved. 448402Sbostic * 556950Sbostic * %sccs.include.redist.c% 634121Sbostic */ 724592Szliu 834121Sbostic #ifndef lint 9*57130Smcilroy static char sccsid[] = "@(#)erf.c 5.5 (Berkeley) 12/14/92"; 1034121Sbostic #endif /* not lint */ 1134121Sbostic 12*57130Smcilroy /* Modified Nov 30, 1992 P. McILROY: 13*57130Smcilroy * Replaced expansions for x >= 1.25 (error 1.7ulp vs ~6ulp) 14*57130Smcilroy * Replaced even+odd with direct calculation for x < .84375, 15*57130Smcilroy * to avoid destructive cancellation. 1656950Sbostic * 17*57130Smcilroy * Performance of erfc(x): 18*57130Smcilroy * In 300000 trials in the range [.83, .84375] the 19*57130Smcilroy * maximum observed error was 3.6ulp. 2056950Sbostic * 21*57130Smcilroy * In [.84735,1.25] the maximum observed error was <2.5ulp in 22*57130Smcilroy * 100000 runs in the range [1.2, 1.25]. 2356950Sbostic * 24*57130Smcilroy * In [1.25,26] (Not including subnormal results) 25*57130Smcilroy * the error is < 1.7ulp. 2656950Sbostic */ 2724592Szliu 2856950Sbostic /* double erf(double x) 2956950Sbostic * double erfc(double x) 3056950Sbostic * x 3156950Sbostic * 2 |\ 3256950Sbostic * erf(x) = --------- | exp(-t*t)dt 3356950Sbostic * sqrt(pi) \| 3456950Sbostic * 0 3556950Sbostic * 3656950Sbostic * erfc(x) = 1-erf(x) 3756950Sbostic * 3856950Sbostic * Method: 3956950Sbostic * 1. Reduce x to |x| by erf(-x) = -erf(x) 4056950Sbostic * 2. For x in [0, 0.84375] 4156950Sbostic * erf(x) = x + x*P(x^2) 4256950Sbostic * erfc(x) = 1 - erf(x) if x<=0.25 4356950Sbostic * = 0.5 + ((0.5-x)-x*P) if x in [0.25,0.84375] 4456950Sbostic * where 4556950Sbostic * 2 2 4 20 4656950Sbostic * P = P(x ) = (p0 + p1 * x + p2 * x + ... + p10 * x ) 4756950Sbostic * is an approximation to (erf(x)-x)/x with precision 4856950Sbostic * 4956950Sbostic * -56.45 5056950Sbostic * | P - (erf(x)-x)/x | <= 2 5156950Sbostic * 5256950Sbostic * 5356950Sbostic * Remark. The formula is derived by noting 5456950Sbostic * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) 5556950Sbostic * and that 5656950Sbostic * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 5756950Sbostic * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is 5856950Sbostic * near 0.6174), and by some experiment, 0.84375 is chosen to 5956950Sbostic * guarantee the error is less than one ulp for erf. 6056950Sbostic * 6156950Sbostic * 3. For x in [0.84375,1.25], let s = x - 1, and 6256950Sbostic * c = 0.84506291151 rounded to single (24 bits) 6356950Sbostic * erf(x) = c + P1(s)/Q1(s) 6456950Sbostic * erfc(x) = (1-c) - P1(s)/Q1(s) 6556950Sbostic * |P1/Q1 - (erf(x)-c)| <= 2**-59.06 6656950Sbostic * Remark: here we use the taylor series expansion at x=1. 6756950Sbostic * erf(1+s) = erf(1) + s*Poly(s) 6856950Sbostic * = 0.845.. + P1(s)/Q1(s) 6956950Sbostic * That is, we use rational approximation to approximate 7056950Sbostic * erf(1+s) - (c = (single)0.84506291151) 7156950Sbostic * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] 7256950Sbostic * where 7356950Sbostic * P1(s) = degree 7 poly in s 7456950Sbostic * 75*57130Smcilroy * 4. For x in [1.25, 2]; [2, 4] 76*57130Smcilroy * erf(x) = 1.0 - tiny 77*57130Smcilroy * erfc(x) = (1/x)exp(-x*x-(.5*log(pi) -.5z + R(z)/S(z)) 7856950Sbostic * 79*57130Smcilroy * Where z = 1/(x*x), R is degree 9, and S is degree 3; 80*57130Smcilroy * 81*57130Smcilroy * 5. For x in [4,28] 8256950Sbostic * erf(x) = 1.0 - tiny 83*57130Smcilroy * erfc(x) = (1/x)exp(-x*x-(.5*log(pi)+eps + zP(z)) 8456950Sbostic * 85*57130Smcilroy * Where P is degree 14 polynomial in 1/(x*x). 8656950Sbostic * 8756950Sbostic * Notes: 8856950Sbostic * Here 4 and 5 make use of the asymptotic series 8956950Sbostic * exp(-x*x) 9056950Sbostic * erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) ); 9156950Sbostic * x*sqrt(pi) 9256950Sbostic * 9356950Sbostic * where for z = 1/(x*x) 9456950Sbostic * P(z) ~ z/2*(-1 + z*3/2*(1 + z*5/2*(-1 + z*7/2*(1 +...)))) 9556950Sbostic * 9656950Sbostic * Thus we use rational approximation to approximate 97*57130Smcilroy * erfc*x*exp(x*x) ~ 1/sqrt(pi); 9856950Sbostic * 9956950Sbostic * The error bound for the target function, G(z) for 100*57130Smcilroy * the interval 101*57130Smcilroy * [4, 28]: 102*57130Smcilroy * |eps + 1/(z)P(z) - G(z)| < 2**(-56.61) 103*57130Smcilroy * for [2, 4]: 104*57130Smcilroy * |R(z)/S(z) - G(z)| < 2**(-58.24) 105*57130Smcilroy * for [1.25, 2]: 106*57130Smcilroy * |R(z)/S(z) - G(z)| < 2**(-58.12) 10756950Sbostic * 10856950Sbostic * 6. For inf > x >= 28 10956950Sbostic * erf(x) = 1 - tiny (raise inexact) 11056950Sbostic * erfc(x) = tiny*tiny (raise underflow) 11156950Sbostic * 11256950Sbostic * 7. Special cases: 11356950Sbostic * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, 11456950Sbostic * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, 11556950Sbostic * erfc/erf(NaN) is NaN 11656950Sbostic */ 11724592Szliu 11856950Sbostic #if defined(vax) || defined(tahoe) 11956950Sbostic #define _IEEE 0 12056950Sbostic #define TRUNC(x) (double) (float) (x) 12156950Sbostic #else 12256950Sbostic #define _IEEE 1 12356950Sbostic #define TRUNC(x) *(((int *) &x) + 1) &= 0xf8000000 12456950Sbostic #define infnan(x) 0.0 12556950Sbostic #endif 12624592Szliu 12756950Sbostic #ifdef _IEEE_LIBM 12856950Sbostic /* 12956950Sbostic * redefining "___function" to "function" in _IEEE_LIBM mode 13056950Sbostic */ 13156950Sbostic #include "ieee_libm.h" 13256950Sbostic #endif 13324592Szliu 13456950Sbostic static double 13556950Sbostic tiny = 1e-300, 13656950Sbostic half = 0.5, 13756950Sbostic one = 1.0, 13856950Sbostic two = 2.0, 13956950Sbostic c = 8.45062911510467529297e-01, /* (float)0.84506291151 */ 14056950Sbostic /* 141*57130Smcilroy * Coefficients for approximation to erf in [0,0.84375] 14256950Sbostic */ 14356950Sbostic p0t8 = 1.02703333676410051049867154944018394163280, 14456950Sbostic p0 = 1.283791670955125638123339436800229927041e-0001, 14556950Sbostic p1 = -3.761263890318340796574473028946097022260e-0001, 14656950Sbostic p2 = 1.128379167093567004871858633779992337238e-0001, 14756950Sbostic p3 = -2.686617064084433642889526516177508374437e-0002, 14856950Sbostic p4 = 5.223977576966219409445780927846432273191e-0003, 14956950Sbostic p5 = -8.548323822001639515038738961618255438422e-0004, 15056950Sbostic p6 = 1.205520092530505090384383082516403772317e-0004, 15156950Sbostic p7 = -1.492214100762529635365672665955239554276e-0005, 15256950Sbostic p8 = 1.640186161764254363152286358441771740838e-0006, 15356950Sbostic p9 = -1.571599331700515057841960987689515895479e-0007, 154*57130Smcilroy p10= 1.073087585213621540635426191486561494058e-0008; 15556950Sbostic /* 156*57130Smcilroy * Coefficients for approximation to erf in [0.84375,1.25] 15756950Sbostic */ 158*57130Smcilroy static double 15956950Sbostic pa0 = -2.362118560752659485957248365514511540287e-0003, 16056950Sbostic pa1 = 4.148561186837483359654781492060070469522e-0001, 16156950Sbostic pa2 = -3.722078760357013107593507594535478633044e-0001, 16256950Sbostic pa3 = 3.183466199011617316853636418691420262160e-0001, 16356950Sbostic pa4 = -1.108946942823966771253985510891237782544e-0001, 16456950Sbostic pa5 = 3.547830432561823343969797140537411825179e-0002, 16556950Sbostic pa6 = -2.166375594868790886906539848893221184820e-0003, 16656950Sbostic qa1 = 1.064208804008442270765369280952419863524e-0001, 16756950Sbostic qa2 = 5.403979177021710663441167681878575087235e-0001, 16856950Sbostic qa3 = 7.182865441419627066207655332170665812023e-0002, 16956950Sbostic qa4 = 1.261712198087616469108438860983447773726e-0001, 17056950Sbostic qa5 = 1.363708391202905087876983523620537833157e-0002, 171*57130Smcilroy qa6 = 1.198449984679910764099772682882189711364e-0002; 17256950Sbostic /* 173*57130Smcilroy * log(sqrt(pi)) for large x expansions. 174*57130Smcilroy * The tail (lsqrtPI_lo) is included in the rational 175*57130Smcilroy * approximations. 176*57130Smcilroy */ 177*57130Smcilroy static double 178*57130Smcilroy lsqrtPI_hi = .5723649429247000819387380943226; 17956950Sbostic /* 180*57130Smcilroy * lsqrtPI_lo = .000000000000000005132975581353913; 181*57130Smcilroy * 182*57130Smcilroy * Coefficients for approximation to erfc in [2, 4] 183*57130Smcilroy */ 184*57130Smcilroy static double 185*57130Smcilroy rb0 = -1.5306508387410807582e-010, /* includes lsqrtPI_lo */ 186*57130Smcilroy rb1 = 2.15592846101742183841910806188e-008, 187*57130Smcilroy rb2 = 6.24998557732436510470108714799e-001, 188*57130Smcilroy rb3 = 8.24849222231141787631258921465e+000, 189*57130Smcilroy rb4 = 2.63974967372233173534823436057e+001, 190*57130Smcilroy rb5 = 9.86383092541570505318304640241e+000, 191*57130Smcilroy rb6 = -7.28024154841991322228977878694e+000, 192*57130Smcilroy rb7 = 5.96303287280680116566600190708e+000, 193*57130Smcilroy rb8 = -4.40070358507372993983608466806e+000, 194*57130Smcilroy rb9 = 2.39923700182518073731330332521e+000, 195*57130Smcilroy rb10 = -6.89257464785841156285073338950e-001, 196*57130Smcilroy sb1 = 1.56641558965626774835300238919e+001, 197*57130Smcilroy sb2 = 7.20522741000949622502957936376e+001, 198*57130Smcilroy sb3 = 9.60121069770492994166488642804e+001; 199*57130Smcilroy /* 200*57130Smcilroy * Coefficients for approximation to erfc in [1.25, 2] 201*57130Smcilroy */ 202*57130Smcilroy static double 203*57130Smcilroy rc0 = -2.47925334685189288817e-007, /* includes lsqrtPI_lo */ 204*57130Smcilroy rc1 = 1.28735722546372485255126993930e-005, 205*57130Smcilroy rc2 = 6.24664954087883916855616917019e-001, 206*57130Smcilroy rc3 = 4.69798884785807402408863708843e+000, 207*57130Smcilroy rc4 = 7.61618295853929705430118701770e+000, 208*57130Smcilroy rc5 = 9.15640208659364240872946538730e-001, 209*57130Smcilroy rc6 = -3.59753040425048631334448145935e-001, 210*57130Smcilroy rc7 = 1.42862267989304403403849619281e-001, 211*57130Smcilroy rc8 = -4.74392758811439801958087514322e-002, 212*57130Smcilroy rc9 = 1.09964787987580810135757047874e-002, 213*57130Smcilroy rc10 = -1.28856240494889325194638463046e-003, 214*57130Smcilroy sc1 = 9.97395106984001955652274773456e+000, 215*57130Smcilroy sc2 = 2.80952153365721279953959310660e+001, 216*57130Smcilroy sc3 = 2.19826478142545234106819407316e+001; 217*57130Smcilroy /* 218*57130Smcilroy * Coefficients for approximation to erfc in [4,28] 21956950Sbostic */ 220*57130Smcilroy static double 221*57130Smcilroy rd0 = -2.1491361969012978677e-016, /* includes lsqrtPI_lo */ 222*57130Smcilroy rd1 = -4.99999999999640086151350330820e-001, 223*57130Smcilroy rd2 = 6.24999999772906433825880867516e-001, 224*57130Smcilroy rd3 = -1.54166659428052432723177389562e+000, 225*57130Smcilroy rd4 = 5.51561147405411844601985649206e+000, 226*57130Smcilroy rd5 = -2.55046307982949826964613748714e+001, 227*57130Smcilroy rd6 = 1.43631424382843846387913799845e+002, 228*57130Smcilroy rd7 = -9.45789244999420134263345971704e+002, 229*57130Smcilroy rd8 = 6.94834146607051206956384703517e+003, 230*57130Smcilroy rd9 = -5.27176414235983393155038356781e+004, 231*57130Smcilroy rd10 = 3.68530281128672766499221324921e+005, 232*57130Smcilroy rd11 = -2.06466642800404317677021026611e+006, 233*57130Smcilroy rd12 = 7.78293889471135381609201431274e+006, 234*57130Smcilroy rd13 = -1.42821001129434127360582351685e+007; 23524592Szliu 236*57130Smcilroy double nerf(x) 23756950Sbostic double x; 23856950Sbostic { 239*57130Smcilroy double R,S,P,Q,ax,s,y,z,r,fabs(),exp(); 24056950Sbostic if(!finite(x)) { /* erf(nan)=nan */ 24156950Sbostic if (isnan(x)) 24256950Sbostic return(x); 24356950Sbostic return (x > 0 ? one : -one); /* erf(+/-inf)= +/-1 */ 24424592Szliu } 24556950Sbostic if ((ax = x) < 0) 24656950Sbostic ax = - ax; 24756950Sbostic if (ax < .84375) { 24856950Sbostic if (ax < 3.7e-09) { 24956950Sbostic if (ax < 1.0e-308) 25056950Sbostic return 0.125*(8.0*x+p0t8*x); /*avoid underflow */ 25156950Sbostic return x + p0*x; 25256950Sbostic } 25356950Sbostic y = x*x; 254*57130Smcilroy r = y*(p1+y*(p2+y*(p3+y*(p4+y*(p5+ 255*57130Smcilroy y*(p6+y*(p7+y*(p8+y*(p9+y*p10))))))))); 25656950Sbostic return x + x*(p0+r); 25724592Szliu } 25856950Sbostic if (ax < 1.25) { /* 0.84375 <= |x| < 1.25 */ 25956950Sbostic s = fabs(x)-one; 26056950Sbostic P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); 26156950Sbostic Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); 26256950Sbostic if (x>=0) 26356950Sbostic return (c + P/Q); 26456950Sbostic else 26556950Sbostic return (-c - P/Q); 26656950Sbostic } 26756950Sbostic if (ax >= 6.0) { /* inf>|x|>=6 */ 26856950Sbostic if (x >= 0.0) 26956950Sbostic return (one-tiny); 27056950Sbostic else 27156950Sbostic return (tiny-one); 27256950Sbostic } 27356950Sbostic /* 1.25 <= |x| < 6 */ 274*57130Smcilroy z = -ax*ax; 275*57130Smcilroy s = -one/z; 276*57130Smcilroy if (ax < 2.0) { 277*57130Smcilroy R = rc0+s*(rc1+s*(rc2+s*(rc3+s*(rc4+s*(rc5+ 278*57130Smcilroy s*(rc6+s*(rc7+s*(rc8+s*(rc9+s*rc10))))))))); 279*57130Smcilroy S = one+s*(sc1+s*(sc2+s*sc3)); 280*57130Smcilroy } else { 281*57130Smcilroy R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+ 282*57130Smcilroy s*(rb6+s*(rb7+s*(rb8+s*(rb9+s*rb10))))))))); 283*57130Smcilroy S = one+s*(sb1+s*(sb2+s*sb3)); 284*57130Smcilroy } 285*57130Smcilroy y = (R/S -.5*s) - lsqrtPI_hi; 286*57130Smcilroy z += y; 287*57130Smcilroy z = exp(z)/ax; 28856950Sbostic if (x >= 0) 28956950Sbostic return (one-z); 29056950Sbostic else 29156950Sbostic return (z-one); 29224592Szliu } 29324592Szliu 294*57130Smcilroy double nerfc(x) 29556950Sbostic double x; 29656950Sbostic { 297*57130Smcilroy double R,S,P,Q,s,ax,y,z,r,fabs(),exp__D(); 29856950Sbostic if (!finite(x)) { 29956950Sbostic if (isnan(x)) /* erfc(NaN) = NaN */ 30056950Sbostic return(x); 30156950Sbostic else if (x > 0) /* erfc(+-inf)=0,2 */ 30256950Sbostic return 0.0; 30356950Sbostic else 30456950Sbostic return 2.0; 30524592Szliu } 30656950Sbostic if ((ax = x) < 0) 30756950Sbostic ax = -ax; 30856950Sbostic if (ax < .84375) { /* |x|<0.84375 */ 30956950Sbostic if (ax < 1.38777878078144568e-17) /* |x|<2**-56 */ 31056950Sbostic return one-x; 31156950Sbostic y = x*x; 312*57130Smcilroy r = y*(p1+y*(p2+y*(p3+y*(p4+y*(p5+ 313*57130Smcilroy y*(p6+y*(p7+y*(p8+y*(p9+y*p10))))))))); 31456950Sbostic if (ax < .0625) { /* |x|<2**-4 */ 31556950Sbostic return (one-(x+x*(p0+r))); 31656950Sbostic } else { 31756950Sbostic r = x*(p0+r); 31856950Sbostic r += (x-half); 31956950Sbostic return (half - r); 32056950Sbostic } 32156950Sbostic } 32256950Sbostic if (ax < 1.25) { /* 0.84375 <= |x| < 1.25 */ 32356950Sbostic s = ax-one; 32456950Sbostic P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); 32556950Sbostic Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); 32656950Sbostic if (x>=0) { 32756950Sbostic z = one-c; return z - P/Q; 32856950Sbostic } else { 32956950Sbostic z = c+P/Q; return one+z; 33056950Sbostic } 33156950Sbostic } 33256950Sbostic if (ax >= 28) /* Out of range */ 33356950Sbostic if (x>0) 33456950Sbostic return (tiny*tiny); 33556950Sbostic else 33656950Sbostic return (two-tiny); 33756950Sbostic z = ax; 33856950Sbostic TRUNC(z); 33956950Sbostic y = z - ax; y *= (ax+z); 34056950Sbostic z *= -z; /* Here z + y = -x^2 */ 34156950Sbostic s = one/(-z-y); /* 1/(x*x) */ 342*57130Smcilroy if (ax >= 4) { /* 6 <= ax */ 343*57130Smcilroy R = s*(rd1+s*(rd2+s*(rd3+s*(rd4+s*(rd5+ 344*57130Smcilroy s*(rd6+s*(rd7+s*(rd8+s*(rd9+s*(rd10 345*57130Smcilroy +s*(rd11+s*(rd12+s*rd13)))))))))))); 346*57130Smcilroy y += rd0; 347*57130Smcilroy } else if (ax >= 2) { 348*57130Smcilroy R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+ 349*57130Smcilroy s*(rb6+s*(rb7+s*(rb8+s*(rb9+s*rb10))))))))); 350*57130Smcilroy S = one+s*(sb1+s*(sb2+s*sb3)); 351*57130Smcilroy y += R/S; 352*57130Smcilroy R = -.5*s; 353*57130Smcilroy } else { 354*57130Smcilroy R = rc0+s*(rc1+s*(rc2+s*(rc3+s*(rc4+s*(rc5+ 355*57130Smcilroy s*(rc6+s*(rc7+s*(rc8+s*(rc9+s*rc10))))))))); 356*57130Smcilroy S = one+s*(sc1+s*(sc2+s*sc3)); 357*57130Smcilroy y += R/S; 358*57130Smcilroy R = -.5*s; 35956950Sbostic } 360*57130Smcilroy /* return exp(-x^2 - lsqrtPI_hi + R + y)/x; */ 361*57130Smcilroy s = ((R + y) - lsqrtPI_hi) + z; 362*57130Smcilroy y = (((z-s) - lsqrtPI_hi) + R) + y; 363*57130Smcilroy r = exp__D(s, y)/x; 36456950Sbostic if (x>0) 36556950Sbostic return r; 36656950Sbostic else 36756950Sbostic return two-r; 36824592Szliu } 369