Skip to content

Commit

Permalink
Improve accuracy of logdiffcdf(::Normal, x, y) (#1728)
Browse files Browse the repository at this point in the history
  • Loading branch information
devmotion authored May 25, 2023
1 parent 4ec511b commit fd58ce1
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Distributions"
uuid = "31c24e10-a181-5473-b8eb-7969acd0382f"
authors = ["JuliaStats"]
version = "0.25.94"
version = "0.25.95"

[deps]
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
Expand Down
9 changes: 9 additions & 0 deletions src/univariate/continuous/normal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ end
# Use Julia implementations in StatsFuns
@_delegate_statsfuns Normal norm μ σ

# `logerf(...)` is more accurate for arguments in the tails than `logsubexp(logcdf(...), logcdf(...))`
function logdiffcdf(d::Normal, x::Real, y::Real)
x < y && throw(ArgumentError("requires x >= y."))
μ, σ = params(d)
_x, _y, _μ, _σ = promote(x, y, μ, σ)
s = sqrt2 *
return logerf((_y - _μ) / s, (_x - _μ) / s) - logtwo
end

gradlogpdf(d::Normal, x::Real) = (d.μ - x) / d.σ^2

mgf(d::Normal, t::Real) = exp(t * d.μ + d.σ^2 / 2 * t^2)
Expand Down
18 changes: 14 additions & 4 deletions test/univariate/continuous/normal.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Test, Distributions, ForwardDiff
using Test, Distributions, StatsFuns, ForwardDiff

isnan_type(::Type{T}, v) where {T} = isnan(v) && v isa T

Expand All @@ -17,9 +17,19 @@ isnan_type(::Type{T}, v) where {T} = isnan(v) && v isa T
@test -Inf === logpdf(Normal(), Inf)
@test iszero(logcdf(Normal(0, 0), 0))
@test iszero(logcdf(Normal(), Inf))
@test logdiffcdf(Normal(), Float32(5), Float32(3)) -6.607938594596893 rtol=1e-12
@test logdiffcdf(Normal(), Float32(5), Float64(3)) -6.607938594596893 rtol=1e-12
@test logdiffcdf(Normal(), Float64(5), Float64(3)) -6.607938594596893 rtol=1e-12
@test @inferred(logdiffcdf(Normal(), 5f0, 3f0)) -6.607938594596893 rtol=1e-12
@test @inferred(logdiffcdf(Normal(), 5f0, 3.0)) -6.607938594596893 rtol=1e-12
@test @inferred(logdiffcdf(Normal(), 5.0, 3.0)) -6.607938594596893 rtol=1e-12
@test_throws ArgumentError logdiffcdf(Normal(), 3, 5)

# Arguments in the tails
logdiffcdf_big(d::Normal, x::Real, y::Real) = logsubexp(logcdf(d, big(y)), logcdf(d, big(x)))
for d in (Normal(), Normal(2.1, 0.1)), (a, b) in ((15, 10), (115, 100), (1015, 1000))
for (x, y) in ((a, b), (-b, -a))
@test isfinite(@inferred(logdiffcdf(d, x, y)))
@test logdiffcdf(d, x, y) logdiffcdf_big(d, x, y)
end
end
let d = Normal(Float64(0), Float64(1)), x = Float64(-60), y = Float64(-60.001)
float_res = logdiffcdf(d, x, y)
big_x = BigFloat(x; precision=100)
Expand Down

2 comments on commit fd58ce1

@devmotion
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/84235

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.25.95 -m "<description of version>" fd58ce19ba18e15cd0c766893c2928e91ad61ad6
git push origin v0.25.95

Please sign in to comment.