]>
git.proxmox.com Git - rustc.git/blob - vendor/rand-0.7.3/src/distributions/poisson.rs
1 // Copyright 2018 Developers of the Rand project.
2 // Copyright 2016-2017 The Rust Project Developers.
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
10 //! The Poisson distribution.
13 use crate::distributions
::utils
::log_gamma
;
14 use crate::distributions
::{Cauchy, Distribution}
;
17 /// The Poisson distribution `Poisson(lambda)`.
19 /// This distribution has a density function:
20 /// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`.
21 #[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
22 #[derive(Clone, Copy, Debug)]
25 // precalculated values
33 /// Construct a new `Poisson` with the given shape parameter
34 /// `lambda`. Panics if `lambda <= 0`.
35 pub fn new(lambda
: f64) -> Poisson
{
36 assert
!(lambda
> 0.0, "Poisson::new called with lambda <= 0");
37 let log_lambda
= lambda
.ln();
40 exp_lambda
: (-lambda
).exp(),
42 sqrt_2lambda
: (2.0 * lambda
).sqrt(),
43 magic_val
: lambda
* log_lambda
- log_gamma(1.0 + lambda
),
48 impl Distribution
<u64> for Poisson
{
49 fn sample
<R
: Rng
+ ?Sized
>(&self, rng
: &mut R
) -> u64 {
50 // using the algorithm from Numerical Recipes in C
52 // for low expected values use the Knuth method
53 if self.lambda
< 12.0 {
56 while p
> self.exp_lambda
{
57 p
*= rng
.gen
::<f64>();
62 // high expected values - rejection method
64 let mut int_result
: u64;
66 // we use the Cauchy distribution as the comparison distribution
68 let cauchy
= Cauchy
::new(0.0, 1.0);
75 // draw from the Cauchy distribution
76 comp_dev
= rng
.sample(cauchy
);
77 // shift the peak of the comparison ditribution
78 result
= self.sqrt_2lambda
* comp_dev
+ self.lambda
;
79 // repeat the drawing until we are in the range of possible values
84 // now the result is a random variable greater than 0 with Cauchy distribution
85 // the result should be an integer value
86 result
= result
.floor();
87 int_result
= result
as u64;
89 // this is the ratio of the Poisson distribution to the comparison distribution
90 // the magic value scales the distribution function to a range of approximately 0-1
91 // since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1
92 // this doesn't change the resulting distribution, only increases the rate of failed drawings
94 * (1.0 + comp_dev
* comp_dev
)
95 * (result
* self.log_lambda
- log_gamma(1.0 + result
) - self.magic_val
).exp();
97 // check with uniform random value - if below the threshold, we are within the target distribution
98 if rng
.gen
::<f64>() <= check
{
110 use crate::distributions
::Distribution
;
113 #[cfg_attr(miri, ignore)] // Miri is too slow
114 fn test_poisson_10() {
115 let poisson
= Poisson
::new(10.0);
116 let mut rng
= crate::test
::rng(123);
119 sum
+= poisson
.sample(&mut rng
);
121 let avg
= (sum
as f64) / 1000.0;
122 println
!("Poisson average: {}", avg
);
123 assert
!((avg
- 10.0).abs() < 0.5); // not 100% certain, but probable enough
127 fn test_poisson_15() {
128 // Take the 'high expected values' path
129 let poisson
= Poisson
::new(15.0);
130 let mut rng
= crate::test
::rng(123);
133 sum
+= poisson
.sample(&mut rng
);
135 let avg
= (sum
as f64) / 1000.0;
136 println
!("Poisson average: {}", avg
);
137 assert
!((avg
- 15.0).abs() < 0.5); // not 100% certain, but probable enough
142 fn test_poisson_invalid_lambda_zero() {
148 fn test_poisson_invalid_lambda_neg() {