Repository navigation
Improve accuracy of log2mexp near log(2) - #140
Merged
Merged
Conversation
Fixes #102. For x > log(3/2), compute log(2 - exp(x)) as log(-2 expm1(x - log(2))) with Cody-Waite argument reduction of x - log(2). The domain (x <= T(log(2))) and the result -Inf at T(log(2)) for Float16/Float32 are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
devmotion
marked this pull request as ready for review
November 12, 2026 21:04
tpapp
approved these changes
Nov 13, 2026
tpapp
left a comment
Collaborator
There was a problem hiding this comment.
Thanks, this looks good to me.
That said, I am not sure that improving the precision of this function is the right way to tackle the problem. Apparently log2mexp is used in two places: the log(c)cdf of the Laplace function, and in tdistinvlogcdf in StatsFuns.
I am pretty sure that the first application at least should be handled as log1mexp(-z-loghalf), before rearranging the formula to use log2mexp. I am still looking at the second one.
Member
Author
|
Since it's part of the public API of the package, I guess it would be good to improve accuracy. But indeed, it might not be the most relevant part of the package and of course downstream packages shouldn't use it if there's numerically better behaved alternatives. |
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.
Fixes #102. Supersedes #139: this is the generic version suggested in the review there, with tests.
Changes
x ≤ log(3/2),log2mexp(x)still computeslog1p(-expm1(x)).x > log(3/2), it computeslog(-2 * expm1(x - log(2))).x - log(2)uses Cody–Waite argument reduction:x - hiwithhi = T(log(2))is exact (Sterbenz lemma, sincex ≥ hi/2), andlo = log(2) - hiis subtracted separately.lois hard-coded for Float16/32/64. Other types use a generic fallback, and a test checks that the hard-coded values match it.BigFloatsubtracts a higher-precisionlog(2)instead, because MPFR rounds that subtraction correctly.log(3/2): atu = -expm1(x) = -1/2both formulas are equally well conditioned. This cutoff gives lower maximum errors than 0.5 for all three float types.x ≤ T(log(2))):T(log(2))rounds abovelog(2)for Float16/Float32. It is whatlog(T(2))andlog2mexp(T(-Inf))return, so it still maps to-Inf, as before. This also keeps theInverseFunctionsround trip working.T(log(2))is belowlog(2), solog2mexp(log(2.0))now returns the correct ≈ -37.6 instead of-Inf.DomainErrorwith a clearer message. Before, the error came fromlog.NaNstill returnsNaN.Accuracy
Maximum error in ulps, measured against a 2048-bit reference:
Performance
log(2)is recomputed at higher precision. On master the results in this range were wrong.Version bumped to 1.0.6. The IrrationalConstants compat (
0.1, 0.2) doesn't need to change: its lowest supported version already providesBigFloat(logtwo; precision=...).🤖 Generated with Claude Code