1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.numerics.special;
39
40 import static org.apache.commons.math3.util.FastMath.PI;
41 import static org.apache.commons.math3.util.FastMath.abs;
42 import static org.apache.commons.math3.util.FastMath.exp;
43 import static org.apache.commons.math3.util.FastMath.floor;
44 import static org.apache.commons.math3.util.FastMath.sqrt;
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public class Erf {
59
60
61
62
63 private static final double sqrtPI = 1.0 / sqrt(PI);
64
65 private static final double oneSixteenth = 1.0 / 16.0;
66 private static final double thresh = 0.46875;
67
68
69
70
71
72 private static final double xSmall = 1.11e-16;
73
74
75
76
77
78
79
80
81
82 private static final double xBig = 26.543;
83
84 private Erf() {
85 }
86
87
88
89
90
91
92
93
94 public static double erf(double arg) {
95 return erfCore(arg, false);
96 }
97
98
99
100
101
102
103
104
105 public static double erfc(double arg) {
106 return erfCore(arg, true);
107 }
108
109
110
111
112
113
114
115
116
117
118 private static double erfCore(double x, boolean mode) {
119
120
121 final double y = abs(x);
122 double result = 0.0;
123
124
125 if (y <= thresh) {
126 double ysq = 0.0;
127 if (y > xSmall) {
128 ysq = y * y;
129 }
130 double xNum = 1.85777706184603153e-1 * ysq;
131 double xDen = ysq;
132 xNum = (xNum + 3.16112374387056560e0) * ysq;
133 xDen = (xDen + 2.36012909523441209e1) * ysq;
134 xNum = (xNum + 1.13864154151050156e2) * ysq;
135 xDen = (xDen + 2.44024637934444173e2) * ysq;
136 xNum = (xNum + 3.77485237685302021e2) * ysq;
137 xDen = (xDen + 1.28261652607737228e3) * ysq;
138 result = x * (xNum + 3.20937758913846947e3) / (xDen + 2.84423683343917062e3);
139 if (mode) {
140 result = 1.0 - result;
141 }
142 } else if (y <= 4.0) {
143
144 double xNum = 2.15311535474403846e-8 * y;
145 double xDen = y;
146 xNum = (xNum + 5.64188496988670089e-1) * y;
147 xDen = (xDen + 1.57449261107098347e1) * y;
148 xNum = (xNum + 8.88314979438837594e0) * y;
149 xDen = (xDen + 1.17693950891312499e2) * y;
150 xNum = (xNum + 6.61191906371416295e1) * y;
151 xDen = (xDen + 5.37181101862009858e2) * y;
152 xNum = (xNum + 2.98635138197400131e2) * y;
153 xDen = (xDen + 1.62138957456669019e3) * y;
154 xNum = (xNum + 8.81952221241769090e2) * y;
155 xDen = (xDen + 3.29079923573345963e3) * y;
156 xNum = (xNum + 1.71204761263407058e3) * y;
157 xDen = (xDen + 4.36261909014324716e3) * y;
158 xNum = (xNum + 2.05107837782607147e3) * y;
159 xDen = (xDen + 3.43936767414372164e3) * y;
160 result = (xNum + 1.23033935479799725e3) / (xDen + 1.23033935480374942e3);
161 double ysq = floor(16.0 * y) * oneSixteenth;
162 double del = (y - ysq) * (y + ysq);
163 result = exp(-ysq * ysq - del) * result;
164 if (!mode) {
165 result = 1.0 - result;
166 if (x < 0.0) {
167 result = -result;
168 }
169 } else if (x < 0.0) {
170 result = 2.0 - result;
171 }
172 } else {
173
174 if (y < xBig) {
175 double iy = 1.0 / y;
176 double ysq = iy * iy;
177 double xNum = 1.63153871373020978e-2 * ysq;
178 double xDen = ysq;
179 xNum = (xNum + 3.05326634961232344e-1) * ysq;
180 xDen = (xDen + 2.56852019228982242e0) * ysq;
181 xNum = (xNum + 3.60344899949804439e-1) * ysq;
182 xDen = (xDen + 1.87295284992346047e0) * ysq;
183 xNum = (xNum + 1.25781726111229246e-1) * ysq;
184 xDen = (xDen + 5.27905102951428412e-1) * ysq;
185 xNum = (xNum + 1.60837851487422766e-2) * ysq;
186 xDen = (xDen + 6.05183413124413191e-2) * ysq;
187 result = ysq * (xNum + 6.58749161529837803e-4) / (xDen + 2.33520497626869185e-3);
188 result = (sqrtPI - result) * iy;
189 ysq = floor(16.0 * y) * oneSixteenth;
190 double del = (y - ysq) * (y + ysq);
191 result = exp(-ysq * ysq - del) * result;
192 }
193 if (!mode) {
194 result = 1.0 - result;
195 if (x < 0.0) {
196 result = -result;
197 }
198 } else {
199 if (x < 0.0) {
200 result = 2.0 - result;
201 }
202 }
203 }
204 return result;
205 }
206 }