@@ -23,10 +23,6 @@ use rand::Rng;
23
23
/// This distribution has density function:
24
24
/// `f(k) = λ^k * exp(-λ) / k!` for `k >= 0`.
25
25
///
26
- /// # Known issues
27
- ///
28
- /// See documentation of [`Poisson::new`].
29
- ///
30
26
/// # Plot
31
27
///
32
28
/// The following plot shows the Poisson distribution with various values of `λ`.
@@ -40,7 +36,7 @@ use rand::Rng;
40
36
/// use rand_distr::{Poisson, Distribution};
41
37
///
42
38
/// let poi = Poisson::new(2.0).unwrap();
43
- /// let v = poi.sample(&mut rand::thread_rng());
39
+ /// let v: f64 = poi.sample(&mut rand::thread_rng());
44
40
/// println!("{} is from a Poisson(2) distribution", v);
45
41
/// ```
46
42
#[ derive( Clone , Copy , Debug , PartialEq ) ]
@@ -52,20 +48,23 @@ where
52
48
53
49
/// Error type returned from [`Poisson::new`].
54
50
#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
55
- // Marked non_exhaustive to allow a new error code in the solution to #1312.
56
- #[ non_exhaustive]
57
51
pub enum Error {
58
52
/// `lambda <= 0`
59
53
ShapeTooSmall ,
60
54
/// `lambda = ∞` or `lambda = nan`
61
55
NonFinite ,
56
+ /// `lambda` is too large, see [Poisson::MAX_LAMBDA]
57
+ ShapeTooLarge ,
62
58
}
63
59
64
60
impl fmt:: Display for Error {
65
61
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
66
62
f. write_str ( match self {
67
63
Error :: ShapeTooSmall => "lambda is not positive in Poisson distribution" ,
68
64
Error :: NonFinite => "lambda is infinite or nan in Poisson distribution" ,
65
+ Error :: ShapeTooLarge => {
66
+ "lambda is too large in Poisson distribution, see Poisson::MAX_LAMBDA"
67
+ }
69
68
} )
70
69
}
71
70
}
@@ -125,14 +124,7 @@ where
125
124
/// Construct a new `Poisson` with the given shape parameter
126
125
/// `lambda`.
127
126
///
128
- /// # Known issues
129
- ///
130
- /// Although this method should return an [`Error`] on invalid parameters,
131
- /// some (extreme) values of `lambda` are known to return a [`Poisson`]
132
- /// object which hangs when [sampled](Distribution::sample).
133
- /// Large (less extreme) values of `lambda` may result in successful
134
- /// sampling but with reduced precision.
135
- /// See [#1312](https://github.com/rust-random/rand/issues/1312).
127
+ /// The maximum allowed lambda is [MAX_LAMBDA](Self::MAX_LAMBDA).
136
128
pub fn new ( lambda : F ) -> Result < Poisson < F > , Error > {
137
129
if !lambda. is_finite ( ) {
138
130
return Err ( Error :: NonFinite ) ;
@@ -145,11 +137,25 @@ where
145
137
let method = if lambda < F :: from ( 12.0 ) . unwrap ( ) {
146
138
Method :: Knuth ( KnuthMethod :: new ( lambda) )
147
139
} else {
140
+ if lambda > F :: from ( Self :: MAX_LAMBDA ) . unwrap ( ) {
141
+ return Err ( Error :: ShapeTooLarge ) ;
142
+ }
148
143
Method :: Rejection ( RejectionMethod :: new ( lambda) )
149
144
} ;
150
145
151
146
Ok ( Poisson ( method) )
152
147
}
148
+
149
+ /// The maximum supported value of `lambda`
150
+ ///
151
+ /// This value was selected such that
152
+ /// `MAX_LAMBDA + 1e6 * sqrt(MAX_LAMBDA) < 2^64 - 1`,
153
+ /// thus ensuring that the probability of sampling a value larger than
154
+ /// `u64::MAX` is less than 1e-1000.
155
+ ///
156
+ /// Applying this limit also solves
157
+ /// [#1312](https://github.com/rust-random/rand/issues/1312).
158
+ pub const MAX_LAMBDA : f64 = 1.844e19 ;
153
159
}
154
160
155
161
impl < F > Distribution < F > for KnuthMethod < F >
@@ -232,6 +238,14 @@ where
232
238
}
233
239
}
234
240
241
+ impl Distribution < u64 > for Poisson < f64 > {
242
+ #[ inline]
243
+ fn sample < R : Rng + ?Sized > ( & self , rng : & mut R ) -> u64 {
244
+ // `as` from float to int saturates
245
+ <Poisson < f64 > as Distribution < f64 > >:: sample ( self , rng) as u64
246
+ }
247
+ }
248
+
235
249
#[ cfg( test) ]
236
250
mod test {
237
251
use super :: * ;
0 commit comments