(x: number)
| 330 | |
| 331 | /** |
| 332 | * Winitzki's approximation for the inverse error function, accurate to |
| 333 | * ~2e-3 relative over (-1, 1). Used as the Newton seed for `erfInv()` and |
| 334 | * `bigErfInv()`. |
| 335 | */ |
| 336 | function erfInvApprox(x: number): number { |
| 337 | const a = 0.147; |
| 338 | const ln1mx2 = Math.log(1 - x * x); |
| 339 | const b = 2 / (Math.PI * a) + ln1mx2 / 2; |
| 340 | return Math.sign(x) * Math.sqrt(Math.sqrt(b * b - ln1mx2 / a) - b); |
| 341 | } |
| 342 | |
| 343 | /** |
| 344 | * Inverse Error Function, accurate to full machine (double) precision. |
| 345 | * |
| 346 | * Winitzki's approximation (~3 correct digits) refined with Newton's |
| 347 | * method on the full-precision `erf()`: |
| 348 | * y ← y − (erf(y) − x)·(√π/2)·e^{y²} |
| 349 | * Each iteration doubles the number of correct digits, so 4 iterations |
| 350 | * reach machine precision. |
| 351 | * |
| 352 | * (Previously used a 6-term truncated Maclaurin series, which was only |
| 353 | * ~4-digit accurate at x = 0.5 and diverged badly for |x| → 1.) |
| 354 | */ |
| 355 | export function erfInv(x: number): number { |
| 356 | if (Number.isNaN(x) || x < -1 || x > 1) return NaN; |
| 357 | if (x === 0) return 0; |
| 358 | if (x === 1) return Infinity; |
| 359 | if (x === -1) return -Infinity; |
| 360 | |
| 361 | const sign = x < 0 ? -1 : 1; |
| 362 | const ax = Math.abs(x); |
no test coverage detected