erfc function

double erfc(
  1. double x
)

Returns the complementary error function of x

Special cases are: Erfc(+Inf) = 0 Erfc(-Inf) = 2 Erfc(NaN) = NaN

Implementation

double erfc(double x) {
  const double tiny = 1.0 / (1 << 56); // 2**-56

  // special cases
  if (x.isNaN) return x;
  if (x.isInfinite) {
    if (x.isNegative) return 2.0;
    return 0.0;
  }

  final bool sign = x < 0;
  if (sign) {
    x = -x;
  }

  if (x < 0.84375) {
    // |x| < 0.84375
    double temp;
    if (x < tiny) {
      // |x| < 2**-56
      temp = x;
    } else {
      final double z = x * x;
      final double r = _pp0 + z * (_pp1 + z * (_pp2 + z * (_pp3 + z * _pp4)));
      final double s =
          1 + z * (_qq1 + z * (_qq2 + z * (_qq3 + z * (_qq4 + z * _qq5))));
      final double y = r / s;
      if (x < 0.25) {
        // |x| < 1/4
        temp = x + x * y;
      } else {
        temp = 0.5 + (x * y + (x - 0.5));
      }
    }

    if (sign) {
      return 1 + temp;
    }
    return 1 - temp;
  }

  if (x < 1.25) {
    // 0.84375 <= |x| < 1.25
    final double s = x - 1;
    final double p = _pa0 +
        s *
            (_pa1 +
                s * (_pa2 + s * (_pa3 + s * (_pa4 + s * (_pa5 + s * _pa6)))));
    final double q = 1 +
        s *
            (_qa1 +
                s * (_qa2 + s * (_qa3 + s * (_qa4 + s * (_qa5 + s * _qa6)))));
    if (sign) {
      return 1 + _erx + p / q;
    }
    return 1 - _erx - p / q;
  }

  if (x < 28) {
    // |x| < 28
    final double s = 1 / (x * x);
    double r1;
    double s1;
    if (x < 1 / 0.35) {
      // |x| < 1 / 0.35 ~ 2.857143
      r1 = _ra7;
      r1 += _ra6 + s * r1;
      r1 += _ra5 + s * r1;
      r1 += _ra4 + s * r1;
      r1 += _ra3 + s * r1;
      r1 += _ra2 + s * r1;
      r1 += _ra1 + s * r1;
      r1 += _ra0 + s * r1;

      s1 = _sa8;
      s1 += _sa7 + s * s1;
      s1 += _sa6 + s * s1;
      s1 += _sa5 + s * s1;
      s1 += _sa4 + s * s1;
      s1 += _sa3 + s * s1;
      s1 += _sa2 + s * s1;
      s1 += _sa1 + s * s1;
      s1 += 1 + s * s1;
    } else {
      // |x| >= 1 / 0.35 ~ 2.857143
      if (sign && x > 6) {
        return 2.0; // x < -6
      }
      r1 = _rb6;
      r1 += _rb5 + s * r1;
      r1 += _rb4 + s * r1;
      r1 += _rb3 + s * r1;
      r1 += _rb2 + s * r1;
      r1 += _rb1 + s * r1;
      r1 += _rb0 + s * r1;

      s1 = _sb7;
      s1 += _sb6 + s * s1;
      s1 += _sb5 + s * s1;
      s1 += _sb4 + s * s1;
      s1 += _sb3 + s * s1;
      s1 += _sb2 + s * s1;
      s1 += _sb1 + s * s1;
      s1 += 1 + s * s1;
    }

    final double z = Double.toSingle(x); // pseudo-single (20-bit) precision x
    final double r =
        math.exp(-z * z - 0.5625) * math.exp((z - x) * (z + x) + r1 / s1);
    if (sign) {
      return 2 - r / x;
    }
    return r / x;
  }
  if (sign) {
    return 2.0;
  }
  return 0.0;
}