Skip to content

Commit 8ebbbf8

Browse files
committed
Avoid panic on large alpha for NormalInverseGaussian
The new calculation method avoids calculating alpha*alpha, which could produce `inf` and lead to invalid parameters for InverseGaussian. The new parameter calculation can slightly affect the values sampled by the distribution.
1 parent fe2a875 commit 8ebbbf8

File tree

2 files changed

+13
-4
lines changed

2 files changed

+13
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919
### Fixes
2020
- Fix `Geometric::new` for small `p > 0` where `1 - p` rounds to 1 (#36)
2121
- Fix panic in `FisherF::new` on almost zero parameters (#39)
22+
- Fix panic in `NormalInverseGaussian::new` with very large `alpha` (#40)
2223

2324
## [0.5.2]
2425

src/normal_inverse_gaussian.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use rand::Rng;
88
pub enum Error {
99
/// `alpha <= 0` or `nan`.
1010
AlphaNegativeOrNull,
11+
/// `alpha` is `inf`
12+
AlphaInfinite,
1113
/// `|beta| >= alpha` or `nan`.
1214
AbsoluteBetaNotLessThanAlpha,
1315
}
@@ -18,6 +20,7 @@ impl fmt::Display for Error {
1820
Error::AlphaNegativeOrNull => {
1921
"alpha <= 0 or is NaN in normal inverse Gaussian distribution"
2022
}
23+
Error::AlphaInfinite => "alpha is +infinity in normal inverse Gaussian distribution",
2124
Error::AbsoluteBetaNotLessThanAlpha => {
2225
"|beta| >= alpha or is NaN in normal inverse Gaussian distribution"
2326
}
@@ -73,14 +76,19 @@ where
7376
return Err(Error::AlphaNegativeOrNull);
7477
}
7578

79+
if alpha == F::infinity() {
80+
return Err(Error::AlphaInfinite);
81+
}
82+
7683
if !(beta.abs() < alpha) {
7784
return Err(Error::AbsoluteBetaNotLessThanAlpha);
7885
}
79-
80-
let gamma = (alpha * alpha - beta * beta).sqrt();
81-
86+
// Note: this calculation method for gamma = sqrt(alpha * alpha - beta * beta)
87+
// avoids overflow if alpha is large, ensuring gamma <= alpha, which implies
88+
// (assuming IEEE754 with subnormals) mu = 1.0 / gamma > 1 / F::max_value() > 0.
89+
let r = beta / alpha;
90+
let gamma = alpha * (F::one() - r * r).sqrt();
8291
let mu = F::one() / gamma;
83-
8492
let inverse_gaussian = InverseGaussian::new(mu, F::one()).unwrap();
8593

8694
Ok(Self {

0 commit comments

Comments
 (0)