Repository navigation
Fix BigFloat precision handling and trigonometric range reduction - #792
Open
OlivierHnt wants to merge 14 commits into
Open
OlivierHnt wants to merge 14 commits into
OlivierHnt wants to merge 14 commits into
Conversation
Negation, abs, floor, ceil, trunc and round are exact, but Base computes them for BigFloat at the global precision and rounds to nearest. A bound with more bits than the global precision then lost the enclosure, e.g. -x for x = 1 + 2^-400 at 512 bits gave [-1, -1]. The same happened in mag and mig, so in pown, cosh and abs2, and in the negation of ExactReal. These operations now go through an `_exact` helper that, for BigFloat, returns a result with the precision of the input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sin, cos, tan, cot, sec, csc, sinpi and cospi located the bounds of an interval relative to multiples of π/2 (or 1/2) with BigFloat operations at the global precision, and only kept the position modulo 4. The result was correct only when π was the tightest enclosure, the interval width checks were exact and the global precision was high enough. Otherwise intervals came out wrong or inverted, for example sin of [9.671908032480526e8, 9.671908055277463e8] at a BigFloat precision of 12, or cospi of 512-bit bounds near 1. The multiples m⋅π/2 strictly inside [lo, hi] are exactly the integers m with floor(lo/(π/2)) < m ≤ ceil(hi/(π/2)) - 1. `_quadrant` now returns a lower bound of the first and an upper bound of the second, as exact integers, so the computed set always contains the true one. Each function then returns the hull of its values at lo, hi and at the extrema in that set, or the whole line if the set contains a pole. When the set holds no extremum or pole, the function is monotone on the union of the pieces it covers, with the direction of the first piece. Thin intervals are evaluated directly, and the width checks only shortcut cases that are correct anyway. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
These functions had no Interval methods, so Base computed them as inv(tan(x)), inv(cos(x)) and inv(sin(x)). The result was one ulp wider than the BareInterval methods, and cot of an interval containing a pole of tan, such as [1, 2], gave the whole line decorated trv although cot is defined there. They now call the BareInterval methods and decorate like tan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The division methods involving ExactReal{Bool} returned exact(x / y)
without checking that the quotient is exact. For example
exact(true) / exact(3.0), exact(true) / exact(3) and
exact(2^60 + 1) / exact(true) gave guaranteed intervals that missed the
true value. Integer divisions now go through the same exactness check as
other integer divisions, x / exact(true) returns x, and
exact(true) / y returns a plain number when y is a float.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For a non-integer exponent interval, x^y splits the real part of y into slices around integers. The bounds of the first and last slice were computed as a - kmin and b - kmax with the operations of the bound type, so they could be rounded inward and the result could miss part of the range, for example with 2000-bit BigFloat bounds. They now come from interval subtraction. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The derivative of x^y for a float or irrational y used v^(y - 1), where y - 1 is rounded to nearest. For example the derivative of x^1e-20 at 2 missed the true value. It now uses y - interval(1), like the rule for interval exponents. Integer and rational exponents are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…arget type The extension evaluated the formula of each constant at the global BigFloat precision, so at a low precision, e.g. setprecision(BigFloat, 20), interval(IrrationalConstants.twoπ) was a loose Float64 enclosure. The formula is now evaluated with 64 more bits than the target type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mid used Base arithmetic, which for BigFloat works at the global precision. With bounds more precise than that, the midpoint was rounded back to a bound, e.g. mid([1, 1 + 2^-400]) at 512 bits was 1, so bisect made no progress. The midpoint is now computed at the precision of the bounds, like the other operations on intervals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bareinterval(T, a) for an irrational a is a generated function that computes the interval once. It was defined for every AbstractIrrational, but a generator cannot see methods defined after it, so for the IrrationalConstants extension bareinterval(Float64, c) and bareinterval(c) threw a MethodError, while interval(c) worked. The test recorded the error. The generated method is now restricted to Base irrationals, whose rounding methods are defined in the package. Other irrationals use the same uncached method as interval(c). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #792 +/- ##
==========================================
- Coverage 94.66% 92.83% -1.84%
==========================================
Files 33 33
Lines 3376 3335 -41
==========================================
- Hits 3196 3096 -100
- Misses 180 239 +59 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Contributor
Benchmark Results (Julia v1)Time benchmarks
Memory benchmarks
|
The helper name was easy to confuse with the public `exact`. The new name pairs with `_fround`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On 32-bit systems `2^60` overflows `Int32`, so `2^60 + 1` was 1 and the quotient by `exact(true)` was exact, as it should be. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The quadrant of the lower bound is now called `q` instead of `r`, and a comment states what `_quadrants` returns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The `_midpoint` helpers were placed between the docstring of `mid` and its definition, so the docstring attached to `_midpoint` and the documentation build failed on the `mid` cross references. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The trigonometric tests no longer use Logging, and the comment on the cached irrational constants now names the restricted signature. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Some more findings by Claude... The only 'big' change is the quadrant logic used for trigonometric functions. In fact it supersedes PR #633.
Below is Claude's summary.
Follow-up to #790 / #791. One commit per fix; each commit message explains the bug and the fix.
BigFloat bounds more precise than the global precision (in the spirit of #767, option 2: results keep the precision of their inputs, as
+and-already do)abs,floor,ceil,trunc,round,mag,migandExactRealnegation used Base, which rounds to nearest at the global precision. This made-x,pown,cosh,abs2, … miss the true value. They now go through an exact helper that keeps the input precision.midnow computes at the precision of the bounds; before,bisectcould make no progress.Range reduction of
sin,cos,tan,cot,sec,csc,sinpi,cospiThe old code tracked only the quadrant modulo 4 and relied on exact width checks and on the global precision, so intervals could come out wrong or inverted, e.g. at
setprecision(BigFloat, 12). The new code computes exact integer bounds on the multiples of π/2 (or 1/2) strictly inside the interval. The result is the hull of the endpoint values and the extrema in that set, or the whole line if the set contains a pole. The commit message has the argument. Thin intervals are evaluated directly. It is as fast or faster: normal-size arguments about 35% faster, huge thin arguments about 20× faster.Other fixes
cot,secandcscnow haveIntervalmethods. Before, Base'sinv(tan(x))was one ulp wider, and gavecot([1, 2])as the whole line decoratedtrv.ExactReal{Bool}claimed exactness for inexact quotients, e.g.exact(true) / exact(3.0).^: the exponent slice bounds are now rounded outward.x^yfor a float exponent usedy - 1rounded to nearest (e.g.x^1e-20).bareinterval(Float64, c)threw aMethodErrorbecause the@generatedcache, now limited to Base irrationals, could not see methods defined in the extension.Not included: display rounding (separate work) and uncertainty parsing (#786).
🤖 Generated with Claude Code