Fix catastrophic cancellation in cot/coth/csc/csch near poles#55
Open
chatman-media wants to merge 1 commit into
Open
Fix catastrophic cancellation in cot/coth/csc/csch near poles#55chatman-media wants to merge 1 commit into
chatman-media wants to merge 1 commit into
Conversation
The denominators cos(2a) - cosh(2b) (and the analogous forms in coth, csc and csch) subtract two values that both approach 1 near the pole (a, b -> 0), so a direct evaluation loses all significance and eventually divides by an exactly-zero denominator, returning NaN. For example cot(1e-10 i) returned NaN + Infinity i and coth(1e-8) returned 90071992.5 (a 10% error) instead of ~1e8. Rewrite each denominator using cosh(2x) - 1 = 2 sinh(x)^2 and 1 - cos(2x) = 2 sin(x)^2, which is algebraically identical but free of cancellation. Results are now accurate to machine precision across the whole plane (verified against mpmath). The two existing coth/cot test values are updated to the more accurate output.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
cot,coth,cscandcschlose accuracy — and eventually returnNaN— near their poles.Each is computed as
numerator / dwhere the denominator is a difference of two terms that both approach1as the argument approaches the pole:a, b → 0)cotcos(2a) − cosh(2b)(1 − …) − (1 + …)cothcosh(2a) − cos(2b)(1 + …) − (1 − …)csc½cosh(2b) − ½cos(2a)½(1 + …) − ½(1 − …)cschcos(2b) − cosh(2a)(1 − …) − (1 + …)Subtracting two nearly-equal numbers is catastrophic cancellation: the leading
1s cancel and only rounding noise survives. Once the terms round to exactly1, the denominator becomes0and the result isNaN/Infinity.These functions are real-valued on the real (resp. imaginary) axis, so the error is easy to confirm:
coth(x) → 1/tanh(x),cot(x) → 1/tan(x), etc.Fix
Rewrite each denominator with the algebraically-identical, cancellation-free identities
e.g. for
cot:cos(2a) − cosh(2b) = −(2·sin(a)² + 2·sinh(b)²). No subtraction of near-equal terms, so full precision is retained right up to the pole. The numerators are unchanged.This is the same class of numerical-stability fix as #54 (which addressed
tanhoverflow); the two are disjoint — #54 touches the+coshfamily for large inputs, this touches the−coshfamily for small inputs.Verification
main, with errors up to 10% /NaN, and pass with the fix). Reference values computed with mpmath at 25 digits.1e-1(andNaN) to ~5e-16(machine precision).coth/cottest values were updated — the new outputs match mpmath exactly (the old ones were off by 1 ulp), mirroring the test update in Improve numerical stability oftanh#54.dist/*rebuilt withcrude-build.