Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure BTPE is not entered when np < 10 #1484

Merged
merged 26 commits into from
Oct 3, 2024
Merged
Changes from 2 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8c229a4
Make sure BTPE is not entered when np < 10
benjamin-lieser Aug 5, 2024
a1c5229
Use Poisson when BINV would fail because of q == 1.0
benjamin-lieser Aug 5, 2024
1928b8c
binomial enable precomputation of values
benjamin-lieser Aug 15, 2024
9354f9b
serde impls
benjamin-lieser Aug 15, 2024
afb619d
benches/distr: use g.finish()
dhardy Sep 13, 2024
f91933b
benches/distr: revise groups/names
dhardy Sep 13, 2024
0105cbe
benches/distr: reduce warm-up and measurement time
dhardy Sep 13, 2024
307c4a9
benches/distr: use elements, not bytes; remove most sample loops
dhardy Sep 13, 2024
5ca3b18
benches/distr: inline distr!
dhardy Sep 13, 2024
3bb85ca
benches/distr: expand Poisson benchmarks
dhardy Sep 13, 2024
8c4b34e
Poisson: split repr into two enum variants
dhardy Sep 13, 2024
2dee225
Make poisson::KnuthMethod pub(crate)
dhardy Sep 13, 2024
361404e
Merge remote-tracking branch 'dhardy/poisson-enum' into binomial_nume…
benjamin-lieser Sep 13, 2024
aaa08df
Use Knuth Method in Binomial to save space in the Binomial struct
benjamin-lieser Sep 13, 2024
a8bfec1
serde impls
benjamin-lieser Sep 13, 2024
a007613
rename inner to method
benjamin-lieser Sep 13, 2024
b0021aa
remove the known issue from doc
benjamin-lieser Sep 13, 2024
2f6cef5
rustfmt and changelog
benjamin-lieser Sep 13, 2024
333f302
code comments and inline attr
benjamin-lieser Sep 13, 2024
487177c
rustfmt
benjamin-lieser Sep 13, 2024
32e16b3
merge with final poisson
benjamin-lieser Sep 24, 2024
32a6655
remove inline
benjamin-lieser Sep 24, 2024
7a66486
move flipped and n into variants
benjamin-lieser Sep 30, 2024
0318978
correct CHANGELOG
benjamin-lieser Oct 1, 2024
fd9d620
put flipped directly into the enum variants
benjamin-lieser Oct 1, 2024
9fb68a0
replace npq with m
benjamin-lieser Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 25 additions & 17 deletions rand_distr/src/binomial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

//! The binomial distribution `Binomial(n, p)`.

use crate::{Distribution, Uniform};
use crate::{Distribution, Poisson, Uniform};
use core::cmp::Ordering;
use core::fmt;
#[allow(unused_imports)]
Expand Down Expand Up @@ -129,25 +129,31 @@ impl Distribution<u64> for Binomial {
// When n*p < 10, so is n*p*q which is the variance, so a result > 110 would be 100 / sqrt(10) = 31 standard deviations away.
const BINV_MAX_X: u64 = 110;

if (self.n as f64) * p < BINV_THRESHOLD && self.n <= (i32::MAX as u64) {
if (self.n as f64) * p < BINV_THRESHOLD {
// Use the BINV algorithm.
let s = p / q;
let a = ((self.n + 1) as f64) * s;

result = 'outer: loop {
let mut r = q.powi(self.n as i32);
let mut u: f64 = rng.random();
let mut x = 0;

while u > r {
u -= r;
x += 1;
if x > BINV_MAX_X {
continue 'outer;

if q == 1.0 {
// p was to small for BINV, we use the Poisson approximation which is very precise for this case
result = Poisson::new(self.n as f64 * p).unwrap().sample(rng) as u64;
} else {
let s = p / q;
let a = (self.n as f64 + 1.0) * s;

result = 'outer: loop {
let mut r = q.powf(self.n as f64);
let mut u: f64 = rng.random();
let mut x = 0;

while u > r {
u -= r;
x += 1;
if x > BINV_MAX_X {
continue 'outer;
}
r *= a / (x as f64) - s;
}
r *= a / (x as f64) - s;
break x;
}
break x;
}
} else {
// Use the BTPE algorithm.
Expand Down Expand Up @@ -358,6 +364,8 @@ mod test {
test_binomial_mean_and_variance(40, 0.5, &mut rng);
test_binomial_mean_and_variance(20, 0.7, &mut rng);
test_binomial_mean_and_variance(20, 0.5, &mut rng);
test_binomial_mean_and_variance(1 << 61, 1e-17, &mut rng);
test_binomial_mean_and_variance(u64::MAX, 1e-19, &mut rng);
}

#[test]
Expand Down