vnl_erf.cxx
Go to the documentation of this file.
1 // This is core/vnl/vnl_erf.cxx
2 #include "vnl_erf.h"
3 //:
4 // \file
5 // \brief Complete and incomplete gamma function approximations
6 // \author Tim Cootes
7 // Translated from NETLIB/SPECFUN/erf by Ian Scott
8 // Original SPECFUN fortran based on
9 // the main computation evaluates near-minimax approximations
10 // from "Rational Chebyshev approximations for the error function"
11 // by W. J. Cody, Math. Comp., 1969, PP. 631-638.
12 
13 double vnl_erfc(double x)
14 {
15  // Initialized data
16 
17  constexpr double thresh = .46875;
18  constexpr double xbig = 26.543;
19  const double xhuge = 6.71e7;
20  const double xmax = 2.53e307;
21 
22  const double c[9] = { .564188496988670089,8.88314979438837594,
23  66.1191906371416295,298.635138197400131,881.95222124176909,
24  1712.04761263407058,2051.07837782607147,1230.33935479799725,
25  2.15311535474403846e-8 };
26  const double d[8] = { 15.7449261107098347,117.693950891312499,
27  537.181101862009858,1621.38957456669019,3290.79923573345963,
28  4362.61909014324716,3439.36767414372164,1230.33935480374942 };
29  const double p[6] = { .305326634961232344,.360344899949804439,
30  .125781726111229246,.0160837851487422766,6.58749161529837803e-4,
31  .0163153871373020978 };
32  const double q[5] = { 2.56852019228982242,1.87295284992346047,
33  .527905102951428412,.0605183413124413191,.00233520497626869185 };
34  constexpr double sqrpi = .56418958354775628695;
35 
36 
37  // Local variables
38  double xden, xnum, result;
39  int i;
40  double y, del, ysq;
41 
42  // ------------------------------------------------------------------
43 
44  // This packet evaluates erf(x), erfc(x), and exp(x*x)*erfc(x)
45  // for a real argument x. It contains three FUNCTION type
46  // subprograms: ERF, ERFC, and ERFCX (or DERF, DERFC, and DERFCX),
47  // and one SUBROUTINE type subprogram, CALERF. The calling
48  // statements for the primary entries are:
49  //
50  // Y=ERF(X) (or Y=DERF(X)),
51  //
52  // Y=ERFC(X) (or Y=DERFC(X)),
53  // and
54  // Y=ERFCX(X) (or Y=DERFCX(X)).
55  //
56  // The routine CALERF is intended for internal packet use only,
57  // all computations within the packet being concentrated in this
58  // routine. The function subprograms invoke CALERF with the
59  // statement
60  //
61  // CALL CALERF(ARG,RESULT,JINT)
62  //
63  // where the parameter usage is as follows
64  //
65  // Function Parameters for CALERF
66  // call ARG Result JINT
67  //
68  // ERF(ARG) ANY REAL ARGUMENT ERF(ARG) 0
69  // ERFC(ARG) ABS(ARG) .LT. XBIG ERFC(ARG) 1
70  // ERFCX(ARG) XNEG .LT. ARG .LT. XMAX ERFCX(ARG) 2
71  //
72  // The main computation evaluates near-minimax approximations
73  // from "Rational Chebyshev approximations for the error function"
74  // by W. J. Cody, Math. Comp., 1969, PP. 631-638. This
75  // transportable program uses rational functions that theoretically
76  // approximate erf(x) and erfc(x) to at least 18 significant
77  // decimal digits. The accuracy achieved depends on the arithmetic
78  // system, the compiler, the intrinsic functions, and proper
79  // selection of the machine-dependent constants.
80  //
81  // *******************************************************************
82  // *******************************************************************
83  //
84  // Explanation of machine-dependent constants
85  //
86  // XMIN = the smallest positive floating-point number.
87  // XINF = the largest positive finite floating-point number.
88  // XNEG = the largest negative argument acceptable to ERFCX;
89  // the negative of the solution to the equation
90  // 2*exp(x*x) = XINF.
91  // XSMALL = argument below which erf(x) may be represented by
92  // 2*x/sqrt(pi) and above which x*x will not underflow.
93  // A conservative value is the largest machine number X
94  // such that 1.0 + X = 1.0 to machine precision.
95  // XBIG = largest argument acceptable to ERFC; solution to
96  // the equation: W(x) * (1-0.5/x**2) = XMIN, where
97  // W(x) = exp(-x*x)/[x*sqrt(pi)].
98  // XHUGE = argument above which 1.0 - 1/(2*x*x) = 1.0 to
99  // machine precision. A conservative value is
100  // 1/[2*sqrt(XSMALL)]
101  // XMAX = largest acceptable argument to ERFCX; the minimum
102  // of XINF and 1/[sqrt(pi)*XMIN].
103  //
104  // Approximate values for some important machines are:
105  //
106  // XMIN XINF XNEG XSMALL XBIG XHUGE XMAX
107  //
108  // CDC 7600 (S.P.) 3.13E-294 1.26E+322 -27.220 7.11E-1 25.922 8.39E+6 1.80X+293 5
109  // CRAY-1 (S.P.) 4.58E-2467 5.45E+2465 -75.345 7.11E-1 75.326 8.39E+6 5.45E+24655
110  // IEEE(IBM/XT,SUN,..) (S.P.) 1.18E-38 3.40E+38 -9.382 5.96E-8 9.194 2.90E+3 4.79E+37
111  // IEEE(IBM/XT,SUN,..) (D.P.) 2.23D-308 1.79D+308 -26.628 1.11D-1 26.543 6.71D+7 2.53D+307 6
112  // IBM 195 (D.P.) 5.40D-79 7.23E+75 -13.190 1.39D-1 13.306 1.90D+8 7.23E+75 7
113  // UNIVAC 1108 (D.P.) 2.78D-309 8.98D+307 -26.615 1.73D-1 26.582 5.37D+8 8.98D+307 8
114  // VAX D-Format (D.P.) 2.94D-39 1.70D+38 -9.345 1.39D-1 9.269 1.90D+8 1.70D+38 7
115  // VAX G-Format (D.P.) 5.56D-309 8.98D+307 -26.615 1.11D-1 26.569 6.71D+7 8.98D+307 6
116 
117  // *******************************************************************
118  // *******************************************************************
119 
120  // Error returns
121  //
122  // The program returns ERFC = 0 for ARG .GE. XBIG;
123  //
124  // ERFCX = XINF for ARG .LT. XNEG;
125  // and
126  // ERFCX = 0 for ARG .GE. XMAX.
127 
128 
129  // Intrinsic functions required are:
130  //
131  // ABS, AINT, EXP
132 
133 
134  // Author: W. J. Cody
135  // Mathematics and Computer Science Division
136  // Argonne National Laboratory
137  // Argonne, IL 60439
138  //
139  // Latest modification: March 19, 1990
140 
141  y = std::abs(x);
142  // ------------------------------------------------------------------
143  // Evaluate erfc for |X| <= 0.46875
144  // ------------------------------------------------------------------
145  if (y <= thresh)
146  return 1 - vnl_erf(x);
147 
148  // ------------------------------------------------------------------
149  // Evaluate erfc for 0.46875 <= |X| <= 4.0
150  // ------------------------------------------------------------------
151  else if (y <= 4.0)
152  {
153  xnum = c[8] * y;
154  xden = y;
155  for (i = 0; i < 7; ++i)
156  {
157  xnum = (xnum + c[i]) * y;
158  xden = (xden + d[i]) * y;
159  }
160  result = (xnum + c[7]) / (xden + d[7]);
161  ysq = std::floor(y * 16.0) / 16.0;
162  del = (y - ysq) * (y + ysq);
163  result = std::exp(-ysq * ysq) * std::exp(-del) * result;
164 
165  // ------------------------------------------------------------------
166  // Evaluate erfc for |X| > 4.0
167  // ------------------------------------------------------------------
168  }
169  else
170  {
171  if (y >= xhuge)
172  {
173  if (y < xmax)
174  result = sqrpi / y;
175  else
176  result = 0;
177  }
178  else if (y >= xbig)
179  result = 0;
180  else
181  {
182  ysq = 1.0 / (y * y);
183  xnum = p[5] * ysq;
184  xden = ysq;
185  for (unsigned i = 0; i < 4; ++i)
186  {
187  xnum = (xnum + p[i]) * ysq;
188  xden = (xden + q[i]) * ysq;
189  }
190  result = ysq * (xnum + p[4]) / (xden + q[4]);
191  result = (sqrpi - result) / y;
192  ysq = std::floor(y * 16.0) / 16.0;
193  del = (y - ysq) * (y + ysq);
194  result = std::exp(-ysq * ysq) * std::exp(-del) * result;
195  }
196  }
197  // ------------------------------------------------------------------
198  // Fix up for negative argument, erf, etc.
199  // ------------------------------------------------------------------
200  if (x < 0.0)
201  result = 2.0 - result;
202  return result;
203 }
Error Function (erf) approximations.
double vnl_erf(double x)
The Error function.
Definition: vnl_erf.h:16
double vnl_erfc(double x)
The Complementary Error function.
Definition: vnl_erf.cxx:13
vnl_bignum abs(vnl_bignum const &x)
Definition: vnl_bignum.h:432
vnl_decnum floor(vnl_decnum const &x)
Definition: vnl_decnum.h:401