Repository navigation
Conversation
`1 + cos(x)` loses significant digits as `cos(x)` approaches `-1`, i.e., for `x` near odd multiples of pi: `vercos( Math.PI + 1e-6 )` returned `5.0004e-13` for a value of `5.0000e-13`, and closer to pi the result has no correct digits. Use the half-angle identities `vercos(x) = 2*cos(x/2)^2` and `havercos(x) = cos(x/2)^2`, which are within 2 ULP everywhere. Regenerate the fixtures in extended precision and add fixtures near odd multiples of pi.
Coverage Report
The above coverage report was generated for the changes in this PR. |
|
@anandkaranubc Mind taking a look at this? Quick glance suggests some clean-up is needed:
Furthermore, I am not sure about the test fixture generation approach. Simply hardcoding the half-angle implementation when generating test fixtures seems incorrect. Instead, we should compute the quantities at higher-precision using the textbook formula, truncate to double, and then compare that we, in fact, retain and improve accuracy by moving to using the identity. Stated otherwise, use of the identity is an implementation detail. We should NOT be generating test fixtures which simply regurgitate that identity. That degrades the value of the tests. |
- document the half-angle method in the JSDoc and C doc comments instead of an inline comment - use `abs2` to square - generate fixtures from the textbook formula `1 + cos(x)` evaluated at 4096 bits, rather than from the identity used by the implementation, and separate comments from expressions in the Julia runners
|
Thanks for the review. Addressed in 9441496:
|
Move the explanation of the evaluation method out of the function body, as requested in review of stdlib-js#15611.
Description
This pull request:
math/base/special/vercosandmath/base/special/havercos(JS and C) for arguments near odd multiples ofpi. It is the counterpart of fix: avoid cancellation inmath/base/special/versinandhaversin#15609 (versin/haversin).1 + cos(x)cancels whencos(x)is close to-1, so the relative error grows like2e-16/(x - (2k+1)pi)^2, and right next to an odd multiple ofpino digits are correct. The fix uses the exact half-angle identities:vercos(x) = 2*cos(x/2)^2havercos(x) = cos(x/2)^2x/2is exact andcoshandles its own argument reduction, so both functions are within 2 ULP of a 256-bit reference on every fixture, including huge|x|.Related Issues
This pull request has the following related issues:
math/base/special/versinandhaversin#15609Questions
No.
Other
1.0 .+ cos.( x )in double precision, which recorded the cancellation. They now evaluate the same textbook formula at 4096 bits and round toFloat64, independent of the identity the implementation uses. There is a newnear_odd_pi.json(4,000 points at(2k+1)*pi +/- dforkin-10:9anddlog-spaced over[1e-12, 0.1]). Ondevelop, 3,990 of those 4,000 points are more than 2 ULP off. With this change, all of them are within 2 ULP. The JS fixture tests now allow 2 ULP instead of exact equality. The native tests already allowed 2 ULP, and 8 for huge values.test.jsandtest.native.jsfor both packages, and the EditorConfig lint is clean.Checklist
AI Assistance
If you answered "yes" above, how did you use AI assistance?
Disclosure
This PR was written primarily by Claude Code. The bug was found by comparing every
stats/base/distsfunction against SciPy on random parameters.@stdlib-js/reviewers