public static double ErfComplement(double v0) {
if (v0 >= 30.0) {
return 0.0;
} else if (v0 <= -10.0) {
return 2.0;
}
double a = Math.Abs(v0);
if (a < 0.47) {
return 1.0 - Erf(v0);
}
// Different approximations are required for different ranges of v0
double res;
if (a <= 4.0) {
// Use the approximation method outlined in W. J. Cody's "Rational Chebyshev
// Approximations for the Error Function"
double numer = EvalPolynomial(a, ErfcNumerCoeffs);
double denom = EvalPolynomial(a, ErfcDenomCoeffs);
res = Math.Exp(-a * a) * numer / denom;
} else {
// Use the approximation method introduced by C. Tellambura and A. Annamalai
// in "Efficient Computation of erfc(x) for Large Arguments"
const double h = 0.5;
const double hSquared = 0.25;
const int nTerms = 10;
double sq = a * a;
res = 0.0;
for (int i = nTerms; i > 0; i--) {
double term = i * i * hSquared;
res += Math.Exp(-term) / (term + sq);
}
res = h * a * Math.Exp(-sq) / Math.PI * (res * 2 + 1.0 / sq);
}
if (v0 < 0.0) {
res = 2.0 - res;
}
return res;
}