* Sound enclosure of a step-rounding function on an interval, given its * point-rounding rule. If both endpoints round to the same integer the function * is constant on the interval; otherwise it spans a half-integer jump and the * result is `singular` (mirrors the Floor/Ceil enclosure discipline
( x: Interval, pointRound: (n: number) => number )
| 463 | * moved down until an upper bound of `lo^n` is at or below `vs` (so |
| 464 | * `lo^n ≤ vs` and `lo` is at or below the true root), the upper one up until |
| 465 | * a lower bound of `hi^n` is at or above `vs`. The move doubles at each |
| 466 | * attempt, so an operand whose guess is far out is reached in a few |
| 467 | * attempts instead of one attempt per ulp. |
| 468 | * |
| 469 | * The validation accepts equality, which is what keeps an exact root exact: |
| 470 | * the chain for `1³ = 1` is exact, so neither endpoint moves and |
| 471 | * `nthRoot([8, 8], 3)` is the point 2. |
| 472 | */ |
| 473 | function rootEnclosure(v: number, n: number): Interval { |
| 474 | // 0, +∞ and NaN are their own root, and the first degree is the identity. |
| 475 | if (!(v > 0) || !Number.isFinite(v) || n === 1) return { lo: v, hi: v }; |
| 476 | |
| 477 | // Scale the operand by `2^(n·m)`, which the root undoes by the exact `2^m`. |
| 478 | // The window is `|log₂ vs| ≤ n/2`, so the scaled operand is a double for |
| 479 | // every degree up to the bound below and the product chain stays normal. A |
| 480 | // degree past it needs no scaling anyway: the error of the rounded exponent |
| 481 | // is `|ln v|/n` ulps, which is under an ulp once the degree passes the 745 |