Repository navigation
Conversation
`exp(sigma^2) - 1` cancels for small `sigma` and is `0` for `sigma^2 < 2^-53`. The fixtures are now generated from the textbook formula in extended precision.
Coverage Report
The above coverage report was generated for the changes in this PR. |
| z = setprecision( BigFloat, 2048 ) do | ||
| es2 = exp.( BigFloat.( sigma ) .^ 2 ); | ||
| Float64.( ( es2 .+ 2 ) .* sqrt.( es2 .- 1 ) ) |
There was a problem hiding this comment.
| z = setprecision( BigFloat, 2048 ) do | |
| es2 = exp.( BigFloat.( sigma ) .^ 2 ); | |
| Float64.( ( es2 .+ 2 ) .* sqrt.( es2 .- 1 ) ) | |
| # The skewness is evaluated in extended precision using the textbook formula `(exp(sigma^2) + 2) * sqrt(exp(sigma^2) - 1)`, as subtracting `1` from `exp(sigma^2)` in double precision cancels for small `sigma`. | |
| z = setprecision( BigFloat, 2048 ) do | |
| es2 = exp.( BigFloat.( sigma ) .^ 2 ); | |
| Float64.( ( es2 .+ 2 ) .* sqrt.( es2 .- 1 ) ); |
Also drop the docstring paragraph at lines 26-27. This matches the docs: move comment and style: add semicolon commits on #15774.
There was a problem hiding this comment.
Applied in cffe135: the comment moved into gen, the docstring paragraph dropped, and the semicolon added. The precision is 4096 rather than 2048 because the fixtures now go down to 1e-300; see the other thread.
| s2 = sigma * sigma; | ||
| return ( exp( s2 ) + 2.0 ) * sqrt( expm1( s2 ) ); |
There was a problem hiding this comment.
| s2 = sigma * sigma; | |
| return ( exp( s2 ) + 2.0 ) * sqrt( expm1( s2 ) ); | |
| if ( sigma < 1.0e-8 ) { | |
| // For small `sigma`, skewness = 3*sigma*(1 + 7*sigma^2/12 + ...): | |
| return 3.0 * sigma; | |
| } | |
| s2 = sigma * sigma; | |
| return ( exp( s2 ) + 2.0 ) * sqrt( expm1( s2 ) ); |
On the question in the description: the branch is small enough to include here. Right now skewness( 0.0, 1.0e-163 ) returns 0, and skewness( 0.0, 1.0e-160 ) returns 2.999983300727547e-160 (exact 3.0e-160). 3.0*sigma is within 1 ULP of the exact value for all sigma < 1e-8. The same change applies to src/main.c:45-46, and small_sigma.json could then go down to 1e-300. Okay to fold in, or would you rather do it as a follow-up?
There was a problem hiding this comment.
Folded in (cffe135): 3.0 * sigma for sigma < 1.0e-8 in main.js and src/main.c, and small_sigma.json now runs from 1e-300 to 1e-1, so both branches are under the 1-ULP test.
One catch when extending the fixtures: at sigma = 1e-300, exp(sigma^2) - 1 cancels even at 2048 bits (about 616 digits against 1 + 1e-600), and 7 of the 1000 fixtures came out 1 ULP off against an 8192-bit evaluation. The runner now uses 4096 bits, which matches 16384 bits on all 1000.
…l/skewness` Below `sigma ~ 1e-154`, `sigma^2` underflows and the result decays to `0`. For `sigma < 1e-8` the series `3*sigma*(1 + 7*sigma^2/12 + ...)` is within 1 ULP of `3*sigma`. The small-`sigma` fixtures now reach `1e-300`, which needs 4096 bits for the textbook reference. Signed-off-by: Abhist17 <abhistkamle.170903@gmail.com>
Description
This pull request:
stats/base/dists/lognormal/skewnessas( exp(sigma^2) + 2 ) * sqrt( expm1(sigma^2) )instead of( exp(sigma^2) + 2 ) * sqrt( exp(sigma^2) - 1 )(JS and C).3*sigmaforsigma < 1e-8, where it is within 1 ULP of the series3*sigma*(1 + 7*sigma^2/12 + ...); belowsigma ≈ 1.5e-154sigma^2underflows and the formula above decays to0.exp(sigma^2) - 1cancels whensigmais small, and is0forsigma^2 < 2^-53:Fixtures and tests:
runner.jlnow evaluates the textbook formula in 2048-bitBigFloatinstead ofDistributions.skewness, which uses the same double-precision expression.Distributionsis dropped fromREQUIRE, anddata.jsonis regenerated with the same input ranges.small_sigma.jsonwithsigmalog-spaced over[1e-150, 0.1]. It passes at 1 ULP in JS and native.data.json, the max error goes from 4,598 ULP to 22 ULP. The remaining 22 comes atsigma ≈ 4.6, where the rounding ofsigma^2is multiplied by the size ofexp(sigma^2). The tolerance goes from 0 to 22. The old 0 only held because the fixture used the same double-precision formula.develop, 1,005 of the 1,110 assertions intest.jsfail. With this change they all pass.Related Issues
None. Same cancellation as #15774 (
lognormal/variance).Questions
No.
Other
No.
Checklist
AI Assistance
If you answered "yes" above, how did you use AI assistance?
Disclosure
This PR was written primarily by Claude Code. I found the bug by scanning
stats/base/distsforexp(...) - 1.@stdlib-js/reviewers