Computes an approximation of the error function complement (1 - erf(x)). Precondition: abs(x) >= 1. Otherwise, use ErfImpl. This follows Cephes's f32 implementation of erfc.
| 172 | // |
| 173 | // This follows Cephes's f32 implementation of erfc. |
| 174 | static XlaOp ErfcImpl32(XlaOp x) { |
| 175 | // Coefficients for erfc(f32), from Cephes. |
| 176 | const double kMaxlog = 88.72283905206835; |
| 177 | // erfc(x) = exp(-x^2) P(1/x^2), 1 < x < 2 |
| 178 | static const std::array<float, 9> kErfcPCoefficient{ |
| 179 | +2.326819970068386E-2, -1.387039388740657E-1, +3.687424674597105E-1, |
| 180 | -5.824733027278666E-1, +6.210004621745983E-1, -4.944515323274145E-1, |
| 181 | +3.404879937665872E-1, -2.741127028184656E-1, +5.638259427386472E-1, |
| 182 | }; |
| 183 | // erfc(x) = exp(-x^2) R(1/x^2), 2 <= x < kMaxlog |
| 184 | static const std::array<float, 8> kErfcRCoefficient{ |
| 185 | -1.047766399936249E+1, +1.297719955372516E+1, -7.495518717768503E+0, |
| 186 | +2.921019019210786E+0, -1.015265279202700E+0, +4.218463358204948E-1, |
| 187 | -2.820767439740514E-1, +5.641895067754075E-1, |
| 188 | }; |
| 189 | XlaOp abs_x = Abs(x); |
| 190 | XlaOp z = Exp(-x * x); |
| 191 | XlaOp q = ScalarLike(x, 1) / abs_x; |
| 192 | XlaOp y = q * q; |
| 193 | XlaOp p = Select(Lt(abs_x, ScalarLike(x, 2.0)), |
| 194 | EvaluatePolynomial<float>(y, kErfcPCoefficient), |
| 195 | EvaluatePolynomial<float>(y, kErfcRCoefficient)); |
| 196 | y = z * q * p; |
| 197 | XlaOp y_clamp = Select(Lt(z, ScalarLike(x, -kMaxlog)), ScalarLike(x, 0), y); |
| 198 | return Select(Lt(x, ScalarLike(x, 0)), ScalarLike(x, 2.0) - y_clamp, y_clamp); |
| 199 | } |
| 200 | |
| 201 | // Compute a polynomial approximation of the error function. |
| 202 | // |