Repository navigation
fix: avoid overflow and underflow for scales far from 1 in stats/base/dists/rayleigh/logpdf
#15923
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -25,6 +25,7 @@ var pow = require( '@stdlib/math/base/special/pow' ); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var ln = require( '@stdlib/math/base/special/ln' ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var PINF = require( '@stdlib/constants/float64/pinf' ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var NINF = require( '@stdlib/constants/float64/ninf' ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var FLOAT64_SMALLEST_NORMAL = require( '@stdlib/constants/float64/smallest-normal' ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // MAIN // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -63,7 +64,11 @@ var NINF = require( '@stdlib/constants/float64/ninf' ); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function logpdf( x, sigma ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var s2i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var lq; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var s2; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var x2; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var r; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var q; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isnan( x ) || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isnan( sigma ) || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -79,7 +84,27 @@ function logpdf( x, sigma ) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| s2 = pow( sigma, 2.0 ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| s2i = 1.0 / s2; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ln( s2i * x ) - ( pow( x, 2.0 ) / ( 2.0 * s2 ) ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| x2 = pow( x, 2.0 ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| q = s2i * x; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| s2 >= FLOAT64_SMALLEST_NORMAL && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2.0 * s2 < PINF && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| x2 < PINF && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| q >= FLOAT64_SMALLEST_NORMAL | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ln( q ) - ( x2 / ( 2.0 * s2 ) ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // For `sigma` or `x` far from `1`, forming `sigma^2` or `x^2` overflows or underflows, so evaluate via the ratio `x/sigma` instead. `ln( x/sigma^2 )` is taken directly while that ratio is normal, as subtracting two large logarithms cancels when `x` is close to `sigma^2`... | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| r = x / sigma; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| q = r / sigma; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( q >= FLOAT64_SMALLEST_NORMAL && q < PINF ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lq = ln( q ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if ( r >= FLOAT64_SMALLEST_NORMAL ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lq = ln( r ) - ln( sigma ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lq = ( ln( x ) - ln( sigma ) ) - ln( sigma ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return lq - ( 0.5 * r * r ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
85
to
+107
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Same in |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,6 @@ | |
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import Distributions: logpdf, Rayleigh | ||
| import JSON | ||
|
|
||
| """ | ||
|
|
@@ -39,9 +38,11 @@ julia> gen( x, sigma, \"data.json\" ); | |
| ``` | ||
| """ | ||
| function gen( x, sigma, name ) | ||
| z = Array{Float64}( undef, length(x) ); | ||
| for i in eachindex(x) | ||
| z[ i ] = logpdf( Rayleigh( sigma[i] ), x[i] ); | ||
| # The log PDF is evaluated in extended precision using the textbook formula `ln(x/sigma^2) - x^2/(2*sigma^2)`, as forming `sigma^2` or `x^2` in double precision overflows or underflows for scale parameters far from `1`... | ||
| z = setprecision( BigFloat, 2048 ) do | ||
| X = BigFloat.( x ); | ||
| S = BigFloat.( sigma ); | ||
| Float64.( log.( X ./ ( S .^ 2 ) ) .- ( ( X .^ 2 ) ./ ( 2 .* ( S .^ 2 ) ) ) ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| end | ||
|
|
||
| # Store data to be written to file as a collection: | ||
|
|
@@ -81,3 +82,13 @@ gen( x, sigma, "medium_scale.json" ); | |
| x = rand( 1000 ) .* 20.0; | ||
| sigma = rand( 1000 ) .* 5.0; | ||
| gen( x, sigma, "small_scale.json" ); | ||
|
|
||
| # Tiny scale parameter (`sigma^2` underflows): | ||
| sigma = exp10.( ( rand( 1000 ) .* 45.0 ) .- 200.0 ); | ||
| x = sigma .* exp10.( ( rand( 1000 ) .* 4.0 ) .- 3.0 ); | ||
| gen( x, sigma, "tiny_scale.json" ); | ||
|
|
||
| # Huge scale parameter (`sigma^2` overflows): | ||
| sigma = exp10.( ( rand( 1000 ) .* 45.0 ) .+ 155.0 ); | ||
| x = sigma .* exp10.( ( rand( 1000 ) .* 4.0 ) .- 3.0 ); | ||
| gen( x, sigma, "huge_scale.json" ); | ||
Large diffs are not rendered by default.
Large diffs are not rendered by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks,
logpdf( 1e154, 1e154 )is right now. Ther === PINFguard from the earlier suggestion is still missing, though:logpdf( 1e300, 1e-10 )returnsNaN(Infinity - Infinity) instead of-Infinity. Same inlib/factory.js:94andsrc/main.c:71. Could you add a test for it too? Also,Distributionscan be dropped fromtest/fixtures/julia/REQUIREnow.