From 2e8beaf8e59fe763dadc331cae00f4371359be4e Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sat, 17 Mar 2018 21:42:45 +0100 Subject: [PATCH 1/4] Add gen_bool method to Rng --- src/lib.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index e7df3f414b3..ffbd545ac8d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -537,6 +537,23 @@ pub trait Rng: RngCore { n <= 1 || self.gen_range(0, n) == 0 } + /// Return a bool with a probability `p` of being true. + /// + /// # Example + /// + /// ```rust + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// println!("{}", rng.gen_bool(1.0 / 3.0)); + /// ``` + fn gen_bool(&mut self, p: f64) -> bool { + assert!(p >= 0.0 && p <= 1.0); + // If `p` is constant, this will be evaluated at compile-time. + let p_int = (p * core::u32::MAX as f64) as u32; + p_int > self.gen() + } + /// Return an iterator of random characters from the set A-Z,a-z,0-9. /// /// # Example @@ -1082,6 +1099,15 @@ mod test { assert_eq!(r.gen_weighted_bool(1), true); } + #[test] + fn test_gen_bool() { + let mut r = rng(105); + for _ in 0..5 { + assert_eq!(r.gen_bool(0.0), false); + assert_eq!(r.gen_bool(1.0), true); + } + } + #[test] fn test_choose() { let mut r = rng(107); From 269f3fd4652dd579041fa3e011cc03760632f1de Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sat, 17 Mar 2018 18:25:31 +0100 Subject: [PATCH 2/4] Deprecate Rng::gen_weighted_bool --- src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index ffbd545ac8d..eabd7c55c85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -521,6 +521,7 @@ pub trait Rng: RngCore { /// # Example /// /// ```rust + /// #[allow(deprecated)] /// use rand::{thread_rng, Rng}; /// /// let mut rng = thread_rng(); @@ -532,6 +533,7 @@ pub trait Rng: RngCore { /// // First meaningful use of `gen_weighted_bool`. /// println!("{}", rng.gen_weighted_bool(3)); /// ``` + #[deprecated(since="0.5.0", note="use gen_bool instead")] fn gen_weighted_bool(&mut self, n: u32) -> bool { // Short-circuit after `n <= 1` to avoid panic in `gen_range` n <= 1 || self.gen_range(0, n) == 0 @@ -551,7 +553,7 @@ pub trait Rng: RngCore { assert!(p >= 0.0 && p <= 1.0); // If `p` is constant, this will be evaluated at compile-time. let p_int = (p * core::u32::MAX as f64) as u32; - p_int > self.gen() + self.gen::() <= p_int } /// Return an iterator of random characters from the set A-Z,a-z,0-9. @@ -1093,6 +1095,7 @@ mod test { } #[test] + #[allow(deprecated)] fn test_gen_weighted_bool() { let mut r = rng(104); assert_eq!(r.gen_weighted_bool(0), true); From 19001e6ca1382ad081f2a3ae14d7223dec54cc13 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Tue, 20 Mar 2018 11:02:58 +0100 Subject: [PATCH 3/4] Add benchmarks for gen_bool and SmallRng --- benches/generators.rs | 6 +++++- benches/misc.rs | 28 ++++++++++++++++++++++++++++ src/lib.rs | 6 ++++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/benches/generators.rs b/benches/generators.rs index 525831376e6..16bd6d56af9 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -9,7 +9,8 @@ const BYTES_LEN: usize = 1024; use std::mem::size_of; use test::{black_box, Bencher}; -use rand::{RngCore, Rng, SeedableRng, NewRng, StdRng, OsRng, JitterRng, EntropyRng}; +use rand::{RngCore, Rng, SeedableRng, NewRng}; +use rand::{StdRng, SmallRng, OsRng, JitterRng, EntropyRng}; use rand::{XorShiftRng, Hc128Rng, IsaacRng, Isaac64Rng, ChaChaRng}; use rand::reseeding::ReseedingRng; use rand::prng::hc128::Hc128Core; @@ -37,6 +38,7 @@ gen_bytes!(gen_bytes_hc128, Hc128Rng::new()); gen_bytes!(gen_bytes_isaac, IsaacRng::new()); gen_bytes!(gen_bytes_isaac64, Isaac64Rng::new()); gen_bytes!(gen_bytes_std, StdRng::new()); +gen_bytes!(gen_bytes_small, SmallRng::new()); gen_bytes!(gen_bytes_os, OsRng::new().unwrap()); macro_rules! gen_uint { @@ -61,6 +63,7 @@ gen_uint!(gen_u32_hc128, u32, Hc128Rng::new()); gen_uint!(gen_u32_isaac, u32, IsaacRng::new()); gen_uint!(gen_u32_isaac64, u32, Isaac64Rng::new()); gen_uint!(gen_u32_std, u32, StdRng::new()); +gen_uint!(gen_u32_small, u32, SmallRng::new()); gen_uint!(gen_u32_os, u32, OsRng::new().unwrap()); gen_uint!(gen_u64_xorshift, u64, XorShiftRng::new()); @@ -68,6 +71,7 @@ gen_uint!(gen_u64_hc128, u64, Hc128Rng::new()); gen_uint!(gen_u64_isaac, u64, IsaacRng::new()); gen_uint!(gen_u64_isaac64, u64, Isaac64Rng::new()); gen_uint!(gen_u64_std, u64, StdRng::new()); +gen_uint!(gen_u64_small, u64, SmallRng::new()); gen_uint!(gen_u64_os, u64, OsRng::new().unwrap()); // Do not test JitterRng like the others by running it RAND_BENCH_N times per, diff --git a/benches/misc.rs b/benches/misc.rs index 0d76489e8a2..ccb10fdb9bb 100644 --- a/benches/misc.rs +++ b/benches/misc.rs @@ -3,11 +3,39 @@ extern crate test; extern crate rand; +const RAND_BENCH_N: u64 = 1000; + use test::{black_box, Bencher}; use rand::{SeedableRng, SmallRng, Rng, thread_rng}; use rand::seq::*; +#[bench] +fn misc_gen_bool(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut accum = true; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.gen_bool(0.18); + } + black_box(accum); + }) +} + +#[bench] +fn misc_gen_bool_var(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut p = 0.18; + let mut accum = true; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.gen_bool(p); + p += 0.0001; + } + black_box(accum); + }) +} + #[bench] fn misc_shuffle_100(b: &mut Bencher) { let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index eabd7c55c85..651a44d2082 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -817,7 +817,7 @@ impl NewRng for R { } } -/// The standard RNG. The PRNG algorithm in `StdRng` is choosen to be efficient +/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient /// on the current platform, to be statistically strong and unpredictable /// (meaning a cryptographically secure PRNG). /// @@ -866,7 +866,7 @@ impl SeedableRng for StdRng { } /// An RNG recommended when small state, cheap initialization and good -/// performance are required. The PRNG algorithm in `SmallRng` is choosen to be +/// performance are required. The PRNG algorithm in `SmallRng` is chosen to be /// efficient on the current platform, **without consideration for cryptography /// or security**. The size of its state is much smaller than for `StdRng`. /// @@ -909,10 +909,12 @@ impl SeedableRng for StdRng { pub struct SmallRng(XorShiftRng); impl RngCore for SmallRng { + #[inline(always)] fn next_u32(&mut self) -> u32 { self.0.next_u32() } + #[inline(always)] fn next_u64(&mut self) -> u64 { self.0.next_u64() } From d157ad6254fc1311275a765886ed824d4597862a Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sun, 18 Mar 2018 17:44:14 +0100 Subject: [PATCH 4/4] Use `gen_bool` in Binomial distribution --- src/distributions/binomial.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/distributions/binomial.rs b/src/distributions/binomial.rs index 8599be03bfd..1b4d2194dca 100644 --- a/src/distributions/binomial.rs +++ b/src/distributions/binomial.rs @@ -64,7 +64,7 @@ impl Distribution for Binomial { if expected < 25.0 { let mut lresult = 0.0; for _ in 0 .. self.n { - if rng.gen::() < p { + if rng.gen_bool(p) { lresult += 1.0; } }