Skip to content

Commit 61a0545

Browse files
authored
Fix underflow of logccdf of PGeneralizedGaussian (#1932)
1 parent b6b1535 commit 61a0545

File tree

2 files changed

+43
-7
lines changed

2 files changed

+43
-7
lines changed

src/univariate/continuous/pgeneralizedgaussian.jl

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,37 @@ end
108108
# The CDF of the Gamma distribution provides this, with the necessary 1/Γ(a) normalization.
109109
function cdf(d::PGeneralizedGaussian, x::Real)
110110
μ, α, p = params(d)
111-
v = cdf(Gamma(inv(p), 1), (abs(x - μ) / α)^p)
112-
return (1 + copysign(v, x - μ)) / 2
111+
return _normcdf_pgeneralizedgaussian(p, (x - μ) / α)
113112
end
113+
function ccdf(d::PGeneralizedGaussian, x::Real)
114+
μ, α, p = params(d)
115+
return _normcdf_pgeneralizedgaussian(p, (μ - x) / α)
116+
end
117+
function _normcdf_pgeneralizedgaussian(p::Real, z::Real)
118+
r = abs(z)^p
119+
d = Gamma(inv(p), 1)
120+
if z < 0
121+
return ccdf(d, r) / 2
122+
else
123+
return (1 + cdf(d, r)) / 2
124+
end
125+
end
126+
114127
function logcdf(d::PGeneralizedGaussian, x::Real)
115128
μ, α, p = params(d)
116-
Δ = x - μ
117-
logv = logcdf(Gamma(inv(p), 1), (abs(Δ) / α)^p)
118-
if Δ < 0
119-
return log1mexp(logv) - logtwo
129+
return _normlogcdf_pgeneralizedgaussian(p, (x - μ) / α)
130+
end
131+
function logccdf(d::PGeneralizedGaussian, x::Real)
132+
μ, α, p = params(d)
133+
return _normlogcdf_pgeneralizedgaussian(p, (μ - x) / α)
134+
end
135+
function _normlogcdf_pgeneralizedgaussian(p::Real, z::Real)
136+
r = abs(z)^p
137+
d = Gamma(inv(p), 1)
138+
if z < 0
139+
return logccdf(d, r) - logtwo
120140
else
121-
return log1pexp(logv) - logtwo
141+
return log1pexp(logcdf(d, r)) - logtwo
122142
end
123143
end
124144

test/univariate/continuous/pgeneralizedgaussian.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,20 @@ using Test
106106
# Additional tests, including sampling
107107
test_distr(d, 10^6)
108108
end
109+
110+
# issue #1916
111+
@testset "Underflow in logccdf" begin
112+
d = PGeneralizedGaussian(2.5)
113+
114+
# (c)cdf became more accurate
115+
@test isfinite(log(cdf(d, -5.0)))
116+
@test isfinite(log(ccdf(d, 5.0)))
117+
@test ccdf(d, 5.0) cdf(d, -5.0)
118+
119+
# We have to use -20 to provoke the issue
120+
@test log(cdf(d, -20.0)) === -Inf
121+
@test log(ccdf(d, 20.0)) === -Inf
122+
@test isfinite(logcdf(d, -20.0))
123+
@test logccdf(d, 20.0) logcdf(d, -20.0)
124+
end
109125
end

0 commit comments

Comments
 (0)