diff --git a/benches/distributions.rs b/benches/distributions.rs index ec2906a7353..48fe2c8aa64 100644 --- a/benches/distributions.rs +++ b/benches/distributions.rs @@ -75,11 +75,13 @@ macro_rules! gen_range_int { #[bench] fn $fnn(b: &mut Bencher) { let mut rng = XorShiftRng::new().unwrap(); + let high = $high; b.iter(|| { for _ in 0..::RAND_BENCH_N { - let x: $ty = Range::new($low, $high).sample(&mut rng); + let x: $ty = Range::sample_single($low, high, &mut rng); black_box(x); + black_box(high); } }); b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; diff --git a/benches/generators.rs b/benches/generators.rs index d02d2d43bbd..194039e7972 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -9,8 +9,9 @@ const BYTES_LEN: usize = 1024; use std::mem::size_of; use test::{black_box, Bencher}; -use rand::{Rng, NewSeeded, Sample, SeedFromRng, StdRng, OsRng, JitterRng}; +use rand::{Rng, NewSeeded, Sample, SeedFromRng, StdRng, OsRng, JitterRng, thread_rng}; use rand::prng::*; +use rand::reseeding::{ReseedingRng, ReseedWithNew}; macro_rules! gen_bytes { ($fnn:ident, $gen:ident) => { @@ -102,3 +103,73 @@ fn init_jitter(b: &mut Bencher) { black_box(JitterRng::new().unwrap()); }); } + + + +#[bench] +fn reseeding_xorshift_bytes(b: &mut Bencher) { + let mut rng = ReseedingRng::new(XorShiftRng::new().unwrap(), + 128*1024*1024*1024, + ReseedWithNew); + let mut buf = [0u8; BYTES_LEN]; + b.iter(|| { + for _ in 0..RAND_BENCH_N { + rng.fill_bytes(&mut buf); + black_box(buf); + } + }); + b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; +} + +macro_rules! reseeding_uint { + ($fnn:ident, $ty:ty) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = ReseedingRng::new(XorShiftRng::new().unwrap(), + 128*1024*1024*1024, + ReseedWithNew); + b.iter(|| { + for _ in 0..RAND_BENCH_N { + black_box(rng.gen::<$ty>()); + } + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +reseeding_uint!(reseeding_xorshift_u32, u32); +reseeding_uint!(reseeding_xorshift_u64, u64); + + + +#[bench] +fn gen_bytes_threadrng(b: &mut Bencher) { + let mut rng = thread_rng(); + let mut buf = [0u8; BYTES_LEN]; + b.iter(|| { + for _ in 0..RAND_BENCH_N { + rng.fill_bytes(&mut buf); + black_box(buf); + } + }); + b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; +} + +macro_rules! reseeding_uint { + ($fnn:ident, $ty:ty) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = thread_rng(); + b.iter(|| { + for _ in 0..RAND_BENCH_N { + black_box(rng.gen::<$ty>()); + } + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +reseeding_uint!(gen_u32_threadrng, u32); +reseeding_uint!(gen_u64_threadrng, u64); diff --git a/src/distributions/default.rs b/src/distributions/default.rs index 054598e774f..fab58fae085 100644 --- a/src/distributions/default.rs +++ b/src/distributions/default.rs @@ -11,8 +11,8 @@ //! Generic value creation use Rng; -use distributions::{Distribution, Rand}; -use distributions::uniform::{Uniform, Uniform01, codepoint}; +use distributions::Distribution; +use distributions::uniform::{Uniform, Uniform01, Codepoint}; /// A generic random value distribution. Generates values using what appears to /// be "the best" distribution for each type, but ultimately the choice is arbitrary. @@ -21,10 +21,7 @@ use distributions::uniform::{Uniform, Uniform01, codepoint}; /// /// * [`Uniform`] for integer types /// * [`Uniform01`] for floating point types -/// -/// Makes use of the following methods: -/// -/// * [`codepoint`] for `char` +/// * [`Codepoint`] for `char` /// /// TODO: link #[derive(Debug)] @@ -32,56 +29,53 @@ pub struct Default; // ----- implementations ----- -impl> Distribution for Default { +impl Distribution for Default where Uniform: Distribution{ fn sample(&self, rng: &mut R) -> T { - T::rand(rng, Uniform) + Uniform.sample(rng) } } // FIXME: https://github.com/rust-lang/rust/issues/23341 -// impl> Distribution for Default { +// impl Distribution for Default where Uniform01: Distribution{ // fn sample(&self, rng: &mut R) -> T { -// T::rand(rng, Uniform01) +// Uniform01.sample(rng) // } // } // workaround above issue: impl Distribution for Default { fn sample(&self, rng: &mut R) -> f32 { - f32::rand(rng, Uniform01) + Uniform01.sample(rng) } } impl Distribution for Default { fn sample(&self, rng: &mut R) -> f64 { - f64::rand(rng, Uniform01) + Uniform01.sample(rng) } } impl Distribution for Default { fn sample(&self, rng: &mut R) -> char { - codepoint(rng) + Codepoint.sample(rng) } } #[cfg(test)] mod tests { - use {Rng, thread_rng}; - use distributions::{Rand, Default}; + use {Rng, Sample, thread_rng}; + use distributions::{Default}; #[test] fn test_types() { let rng: &mut Rng = &mut thread_rng(); - fn do_test>(rng: &mut Rng) -> T { - T::rand(rng, Default) - } - do_test::(rng); - do_test::(rng); - do_test::(rng); - do_test::(rng); + rng.sample::(Default); + rng.sample::(Default); + rng.sample::(Default); + rng.sample::(Default); #[cfg(feature = "i128_support")] - do_test::(rng); - do_test::(rng); - do_test::(rng); + rng.sample::(Default); + rng.sample::(Default); + rng.sample::(Default); } } diff --git a/src/distributions/exponential.rs b/src/distributions/exponential.rs index be8616391e2..48a988dee3f 100644 --- a/src/distributions/exponential.rs +++ b/src/distributions/exponential.rs @@ -11,7 +11,7 @@ //! The exponential distribution. use {Rng}; -use distributions::{ziggurat, ziggurat_tables, Distribution, Uniform01, Rand}; +use distributions::{ziggurat, ziggurat_tables, Distribution, Uniform01}; /// Generates Exp(1) random numbers. /// @@ -43,7 +43,7 @@ pub fn exp1(rng: &mut R) -> f64 { } #[inline] fn zero_case(rng: &mut R, _u: f64) -> f64 { - let x = f64::rand(rng, Uniform01); + let x: f64 = Uniform01.sample(rng); ziggurat_tables::ZIG_EXP_R - x.ln() } diff --git a/src/distributions/gamma.rs b/src/distributions/gamma.rs index 93f1a4835c3..5ddbc1cc6c5 100644 --- a/src/distributions/gamma.rs +++ b/src/distributions/gamma.rs @@ -17,7 +17,7 @@ use self::ChiSquaredRepr::*; use {Rng}; use distributions::normal::standard_normal; -use distributions::{Distribution, Exp, Rand, Open01}; +use distributions::{Distribution, Exp, Open01}; /// The Gamma distribution `Gamma(shape, scale)` distribution. /// @@ -145,7 +145,7 @@ impl Distribution for Gamma { } impl Distribution for GammaSmallShape { fn sample(&self, rng: &mut R) -> f64 { - let u = f64::rand(rng, Open01); + let u: f64 = Open01.sample(rng); self.large_shape.sample(rng) * u.powf(self.inv_shape) } @@ -160,7 +160,7 @@ impl Distribution for GammaLargeShape { } let v = v_cbrt * v_cbrt * v_cbrt; - let u = f64::rand(rng, Open01); + let u: f64 = Open01.sample(rng); let x_sqr = x * x; if u < 1.0 - 0.0331 * x_sqr * x_sqr || diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 4c93fe5cc04..6db1a5af15c 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -14,14 +14,11 @@ //! generated values; for example `Range` needs to know its upper and lower //! bounds. Distributions use the `Distribution` trait to yield values: call //! `distr.sample(&mut rng)` to get a random variable. -//! -//! TODO: is it worth exposing both submodules and re-exporting their members? use Rng; pub use self::default::Default; -pub use self::uniform::{uniform, codepoint, ascii_word_char}; -pub use self::uniform::{Uniform, Uniform01, Open01, Closed01, AsciiWordChar}; +pub use self::uniform::{Uniform, Uniform01, Open01, Closed01, Codepoint, AsciiWordChar}; pub use self::range::Range; #[cfg(feature="std")] @@ -79,55 +76,26 @@ impl<'a, T, D: Distribution> Distribution for &'a D { } } -/// Generic trait for sampling random values from some distribution +/// Trait for sampling values from the `Default` distribution. /// -/// TODO: quite possibly remove both this and `SimpleRand` since `Sample` is -/// more convenient and distributions like `Default` handle all the real work. +/// This is mostly a shim around `Default` for backwards compatibility; the +/// implementation is simply `Default.sample(rng)`. /// /// # Example /// ```rust -/// use rand::distributions::{Rand, Default, Range}; +/// use rand::{Rand, thread_rng}; /// -/// let mut rng = rand::thread_rng(); -/// println!("Random byte: {}", u8::rand(&mut rng, Default)); -/// println!("Random range: {}", i32::rand(&mut rng, Range::new(-99, 100))); -/// ``` -pub trait Rand { - /// Generate a random value of the given type, according to the specified - /// distribution. - /// - /// The distributions `Default` (or `Uniform` and `Uniform01`) and `Range` - /// should cover most simpler usages; `Normal`, `LogNormal`, `Exp`, `Gamma` - /// and a few others are also available. - fn rand(rng: &mut R, distr: D) -> Self; -} - -impl> Rand for T { - fn rand(rng: &mut R, distr: D) -> Self { - distr.sample(rng) - } -} - -/// Simpler version of `Rand`, without support for alternative distributions. -/// -/// TODO: decide which version of `Rand` to keep. If this one, rename struct to -/// `Rand` and function to `rand`. -/// -/// # Example -/// ```rust -/// use rand::distributions::SimpleRand; -/// -/// let mut rng = rand::thread_rng(); -/// println!("Random byte: {}", u8::simple_rand(&mut rng)); +/// let mut rng = thread_rng(); +/// println!("Random byte: {}", u8::rand(&mut rng)); /// ``` -pub trait SimpleRand { +pub trait Rand : Sized { /// Generate a random value of the given type, using the `Default` /// distribution. - fn simple_rand(rng: &mut R) -> Self; + fn rand(rng: &mut R) -> Self; } -impl SimpleRand for T where Default: Distribution { - fn simple_rand(rng: &mut R) -> Self { +impl Rand for T where Default: Distribution { + fn rand(rng: &mut R) -> Self { Default.sample(rng) } } @@ -167,7 +135,7 @@ fn ziggurat( // precision of using 64 bits for f64 does not buy us much. // Because for some RNG's the least significant bits can be of lower // statistical quality, we use bits 3..10 for i. - let bits: u64 = uniform(rng); + let bits: u64 = rng.sample(Uniform); // u is either U(-1, 1) or U(0, 1) depending on if this is a // symmetric distribution or not. @@ -192,7 +160,7 @@ fn ziggurat( return zero_case(rng, u); } // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 - if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * f64::rand(rng, Uniform01) < pdf(x) { + if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.sample::(Uniform01) < pdf(x) { return x; } } diff --git a/src/distributions/normal.rs b/src/distributions/normal.rs index 6cda325df46..92664b94a18 100644 --- a/src/distributions/normal.rs +++ b/src/distributions/normal.rs @@ -11,7 +11,7 @@ //! The normal and derived distributions. use {Rng}; -use distributions::{ziggurat, ziggurat_tables, Distribution, Rand, Open01}; +use distributions::{ziggurat, ziggurat_tables, Distribution, Open01}; /// Generates N(0, 1) random numbers /// (a.k.a. a standard normal, or Gaussian). @@ -50,8 +50,8 @@ pub fn standard_normal(rng: &mut R) -> f64 { let mut y = 0.0f64; while -2.0 * y < x * x { - let x_ = f64::rand(rng, Open01); - let y_ = f64::rand(rng, Open01); + let x_: f64 = Open01.sample(rng); + let y_: f64 = Open01.sample(rng); x = x_.ln() / ziggurat_tables::ZIG_NORM_R; y = y_.ln(); diff --git a/src/distributions/range.rs b/src/distributions/range.rs index 06d8ddaf464..9120028de8d 100644 --- a/src/distributions/range.rs +++ b/src/distributions/range.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Generating numbers between two others. +//! A distribution generating numbers within a given range. -use Rand; use Rng; use distributions::{Distribution, Uniform}; use utils::FloatConversions; @@ -18,22 +17,21 @@ use utils::FloatConversions; /// Sample values uniformly between two bounds. /// /// This gives a uniform distribution (assuming the RNG used to sample -/// it is itself uniform & the `RangeImpl` implementation is correct), +/// it is itself uniform and the `RangeImpl` implementation is correct), /// even for edge cases like `low = 0u8`, /// `high = 170u8`, for which a naive modulo operation would return /// numbers less than 85 with double the probability to those greater /// than 85. /// -/// Types should attempt to sample in `[low, high)`, i.e., not -/// including `high`, but this may be very difficult. All the -/// primitive integer types satisfy this property, and the float types -/// normally satisfy it, but rounding may mean `high` can occur. +/// Types should attempt to sample in `[low, high)` for +/// `Range::new(low, high)`, i.e., excluding `high`, but this may be very +/// difficult. All the primitive integer types satisfy this property, and the +/// float types normally satisfy it, but rounding may mean `high` can occur. /// /// # Example /// /// ```rust -/// use rand::distributions::Distribution; -/// use rand::distributions::range::Range; +/// use rand::distributions::{Distribution, Range}; /// /// fn main() { /// let between = Range::new(10, 10000); @@ -50,22 +48,30 @@ pub struct Range { inner: T, } -// Range must be parameterised so that `Self` is fully typed, but we don't -// actually use this type, so we just use any valid type here. (Minor lang bug?) +/// Ignore the `RangeInt` parameterisation; these non-member functions are +/// available to all range types. (Rust requires a type, and won't accept +/// `T: RangeImpl`. Consider this a minor language issue.) impl Range> { - /// Create a new `Range` instance that samples uniformly from - /// `[low, high)`. Panics if `low >= high`. + /// Create a new `Range` instance which samples uniformly from the half + /// open range `[low, high)` (excluding `high`). Panics if `low >= high`. pub fn new(low: X, high: X) -> Range { assert!(low < high, "Range::new called with `low >= high`"); Range { inner: RangeImpl::new(low, high) } } - /// Create a new `Range` instance that samples uniformly from - /// `[low, high]` (inclusive). Panics if `low >= high`. + /// Create a new `Range` instance which samples uniformly from the closed + /// range `[low, high]` (inclusive). Panics if `low >= high`. pub fn new_inclusive(low: X, high: X) -> Range { assert!(low < high, "Range::new called with `low >= high`"); Range { inner: RangeImpl::new_inclusive(low, high) } } + + /// Sample a single value uniformly from `[low, high)`. + /// Panics if `low >= high`. + pub fn sample_single(low: X, high: X, rng: &mut R) -> X { + assert!(low < high, "Range::sample_single called with low >= high"); + X::T::sample_single(low, high, rng) + } } impl Distribution for Range { @@ -74,26 +80,80 @@ impl Distribution for Range { } } -/// Helper trait for creating implementations of `RangeImpl`. +/// Helper trait for creating objects using the correct implementation of +/// `RangeImpl` for the sampling type; this enables `Range::new(a, b)` to work. pub trait SampleRange: PartialOrd+Sized { type T: RangeImpl; } /// Helper trait handling actual range sampling. -pub trait RangeImpl { +/// +/// If you want to implement `Range` sampling for your own type, then +/// implement both this trait and `SampleRange`: +/// +/// ```rust +/// use rand::{Rng, thread_rng, Distribution}; +/// use rand::distributions::range::{Range, SampleRange, RangeImpl, RangeFloat}; +/// +/// #[derive(Clone, Copy, PartialEq, PartialOrd)] +/// struct MyF32(f32); +/// +/// #[derive(Clone, Copy, Debug)] +/// struct RangeMyF32 { +/// inner: RangeFloat, +/// } +/// impl RangeImpl for RangeMyF32 { +/// type X = MyF32; +/// fn new(low: Self::X, high: Self::X) -> Self { +/// RangeMyF32 { +/// inner: RangeFloat::::new(low.0, high.0), +/// } +/// } +/// fn new_inclusive(low: Self::X, high: Self::X) -> Self { +/// RangeImpl::new(low, high) +/// } +/// fn sample(&self, rng: &mut R) -> Self::X { +/// MyF32(self.inner.sample(rng)) +/// } +/// } +/// +/// impl SampleRange for MyF32 { +/// type T = RangeMyF32; +/// } +/// +/// let (low, high) = (MyF32(17.0f32), MyF32(22.0f32)); +/// let range = Range::new(low, high); +/// let x = range.sample(&mut thread_rng()); +/// ``` +pub trait RangeImpl: Sized { /// The type sampled by this implementation. type X: PartialOrd; - /// Construct self. + /// Construct self, with inclusive lower bound and exclusive upper bound + /// `[low, high)`. /// - /// This should not be called directly. `Range::new` asserts that - /// `low < high` before calling this. + /// Usually users should not call this directly but instead use + /// `Range::new`, which asserts that `low < high` before calling this. fn new(low: Self::X, high: Self::X) -> Self; + /// Construct self, with inclusive bounds `[low, high]`. + /// + /// Usually users should not call this directly but instead use + /// `Range::new`, which asserts that `low < high` before calling this. fn new_inclusive(low: Self::X, high: Self::X) -> Self; /// Sample a value. fn sample(&self, rng: &mut R) -> Self::X; + + /// Sample a single value uniformly from a range with inclusive lower bound + /// and exclusive upper bound `[low, high)`. + /// Panics if `low >= high`. + fn sample_single(low: Self::X, high: Self::X, rng: &mut R) + -> Self::X + { + let range: Self = RangeImpl::new(low, high); + range.sample(rng) + } } /// Implementation of `RangeImpl` for integer types. @@ -201,11 +261,11 @@ macro_rules! range_int_impl { // casting is a no-op. let zone = self.zone as $signed as $i_large as $u_large; loop { - let v: $u_large = Rand::rand(rng, Uniform); + let v: $u_large = Uniform.sample(rng); if $use_mult { - let (high, low) = v.wmul(range); - if low <= zone { - return self.low.wrapping_add(high as $ty); + let (hi, lo) = v.wmul(range); + if lo <= zone { + return self.low.wrapping_add(hi as $ty); } } else { if v <= zone { @@ -215,7 +275,38 @@ macro_rules! range_int_impl { } } else { // Sample from the entire integer range. - Rand::rand(rng, Uniform) + Uniform.sample(rng) + } + } + + fn sample_single(low: Self::X, high: Self::X, rng: &mut R) -> Self::X { + let range = (high as $u_large) + .wrapping_sub(low as $u_large); + let zone = + if ::core::$unsigned::MAX <= ::core::u16::MAX as $unsigned { + // Using a modulus is faster than the approximation for + // i8 and i16. I suppose we trade the cost of one + // modulus for near-perfect branch prediction. + let unsigned_max: $u_large = ::core::$u_large::MAX; + let ints_to_reject = (unsigned_max - range + 1) % range; + unsigned_max - ints_to_reject + } else { + // conservative but fast approximation + range << range.leading_zeros() + }; + + loop { + let v: $u_large = Uniform.sample(rng); + if $use_mult { + let (hi, lo) = v.wmul(range); + if lo <= zone { + return low.wrapping_add(hi as $ty); + } + } else { + if v <= zone { + return low.wrapping_add((v % range) as $ty); + } + } } } } @@ -340,14 +431,18 @@ wmul_impl_128! { u128 } #[derive(Clone, Copy, Debug)] pub enum RangeFloat { // A range that is completely positive + #[doc(hidden)] Positive { offset: X, scale: X }, // A range that is completely negative + #[doc(hidden)] Negative { offset: X, scale: X }, // A range that is goes from negative to positive, but has more positive // than negative numbers + #[doc(hidden)] PosAndNeg { cutoff: X, scale: X }, // A range that is goes from negative to positive, but has more negative // than positive numbers + #[doc(hidden)] NegAndPos { cutoff: X, scale: X }, } @@ -457,8 +552,8 @@ range_float_impl! { f64, Rng::next_u64 } #[cfg(test)] mod tests { - use {Rng, thread_rng}; - use distributions::{Rand, Distribution}; + use {Rng, Sample, thread_rng}; + use distributions::{Distribution}; use distributions::range::{Range, RangeImpl, RangeFloat, SampleRange}; #[test] @@ -516,7 +611,7 @@ mod tests { for &(low, high) in v.iter() { let my_range = Range::new(low, high); for _ in 0..1000 { - let v: $ty = Rand::rand(&mut rng, my_range); + let v: $ty = rng.sample(my_range); assert!(low <= v && v < high); } } @@ -542,7 +637,7 @@ mod tests { for &(low, high) in v.iter() { let my_range = Range::new(low, high); for _ in 0..1000 { - let v: $ty = Rand::rand(&mut rng, my_range); + let v: $ty = rng.sample(my_range); assert!(low <= v && v < high); } } @@ -585,7 +680,7 @@ mod tests { let range = Range::new(low, high); let mut rng = ::test::rng(); for _ in 0..100 { - let x = MyF32::rand(&mut rng, range); + let x: MyF32 = rng.sample(range); assert!(low <= x && x < high); } } diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs index fce3b6c9746..afda3ddbc14 100644 --- a/src/distributions/uniform.rs +++ b/src/distributions/uniform.rs @@ -14,55 +14,9 @@ use core::char; use core::mem; use Rng; -use distributions::{Distribution, Rand}; +use distributions::Distribution; use utils::FloatConversions; -// ----- convenience functions ----- - -/// Sample values uniformly over the whole range supported by the type -/// -/// This method has precisely two template parameters. To fix the output type, -/// use the syntax `uniform::(rng)`. -pub fn uniform, R: Rng+?Sized>(rng: &mut R) -> T { - T::rand(rng, Uniform) -} - -/// Sample a `char`, uniformly distributed over all Unicode scalar values, -/// i.e. all code points in the range `0...0x10_FFFF`, except for the range -/// `0xD800...0xDFFF` (the surrogate code points). This includes -/// unassigned/reserved code points. -/// -/// TODO: should this be removed in favour of a distribution? -#[inline] -pub fn codepoint(rng: &mut R) -> char { - // a char is 21 bits - const CHAR_MASK: u32 = 0x001f_ffff; - loop { - // Rejection sampling. About 0.2% of numbers with at most - // 21-bits are invalid codepoints (surrogates), so this - // will succeed first go almost every time. - match char::from_u32(rng.next_u32() & CHAR_MASK) { - Some(c) => return c, - None => {} - } - } -} - -/// Sample a `char`, uniformly distributed over ASCII letters and numbers: -/// a-z, A-Z and 0-9. -/// -/// TODO: should this be removed in favour of `AsciiWordChar`? -#[inline] -pub fn ascii_word_char(rng: &mut R) -> char { - use sequences::Choose; - const GEN_ASCII_STR_CHARSET: &'static [u8] = - b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ - abcdefghijklmnopqrstuvwxyz\ - 0123456789"; - *GEN_ASCII_STR_CHARSET.choose(rng).unwrap() as char -} - - // ----- Sampling distributions ----- /// Sample values uniformly over the whole range supported by the type @@ -81,7 +35,15 @@ pub struct Open01; #[derive(Debug)] pub struct Closed01; -/// Sample values uniformly from the ASCII ranges z-a, A-Z, and 0-9. +/// Sample a `char`, uniformly distributed over all Unicode scalar values, +/// i.e. all code points in the range `0...0x10_FFFF`, except for the range +/// `0xD800...0xDFFF` (the surrogate code points). This includes +/// unassigned/reserved code points. +#[derive(Debug)] +pub struct Codepoint; + +/// Sample a `char`, uniformly distributed over ASCII letters and numbers: +/// a-z, A-Z and 0-9. #[derive(Debug)] pub struct AsciiWordChar; @@ -90,10 +52,12 @@ pub struct AsciiWordChar; impl Distribution for Uniform { fn sample(&self, rng: &mut R) -> isize { - if mem::size_of::() == 4 { - i32::rand(rng, Uniform) as isize + if mem::size_of::() <= 4 { + rng.next_u32() as isize + } else if mem::size_of::() == 8 { + rng.next_u64() as isize } else { - i64::rand(rng, Uniform) as isize + unreachable!() } } } @@ -137,10 +101,12 @@ impl Distribution for Uniform { impl Distribution for Uniform { #[inline] fn sample(&self, rng: &mut R) -> usize { - if mem::size_of::() == 4 { - u32::rand(rng, Uniform) as usize + if mem::size_of::() <= 4 { + rng.next_u32() as usize + } else if mem::size_of::() == 8 { + rng.next_u64() as usize } else { - u64::rand(rng, Uniform) as usize + unreachable!() } } } @@ -238,60 +204,83 @@ float_impls! { f32, Rng::next_u32 } float_impls! { f64, Rng::next_u64 } +impl Distribution for Codepoint { + fn sample(&self, rng: &mut R) -> char { + // a char is 21 bits + const CHAR_MASK: u32 = 0x001f_ffff; + loop { + // Rejection sampling. About 0.2% of numbers with at most + // 21-bits are invalid codepoints (surrogates), so this + // will succeed first go almost every time. + match char::from_u32(rng.next_u32() & CHAR_MASK) { + Some(c) => return c, + None => {} + } + } + } +} + impl Distribution for AsciiWordChar { fn sample(&self, rng: &mut R) -> char { - ascii_word_char(rng) + const RANGE: u32 = 26 + 26 + 10; + const GEN_ASCII_STR_CHARSET: &'static [u8] = + b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789"; + loop { + let var = rng.next_u32() & 0x3F; + if var < RANGE { + return GEN_ASCII_STR_CHARSET[var as usize] as char + } + } } } #[cfg(test)] mod tests { - use {thread_rng, iter}; - use distributions::{Rand, uniform, Uniform, Uniform01, Open01, Closed01}; - use distributions::uniform::{codepoint, ascii_word_char}; + use {Sample, thread_rng, iter}; + use distributions::{Uniform, Uniform01, Open01, Closed01, + Codepoint, AsciiWordChar}; #[test] fn test_integers() { let mut rng = ::test::rng(); - let _: i32 = Rand::rand(&mut rng, Uniform); - let _ = i32::rand(&mut rng, Uniform); - - let _: isize = uniform(&mut rng); - let _: i8 = uniform(&mut rng); - let _: i16 = uniform(&mut rng); - let _: i32 = uniform(&mut rng); - let _: i64 = uniform(&mut rng); + rng.sample::(Uniform); + rng.sample::(Uniform); + rng.sample::(Uniform); + rng.sample::(Uniform); + rng.sample::(Uniform); #[cfg(feature = "i128_support")] - let _: i128 = uniform(&mut rng); + rng.sample::(Uniform); - let _: usize = uniform(&mut rng); - let _: u8 = uniform(&mut rng); - let _: u16 = uniform(&mut rng); - let _: u32 = uniform(&mut rng); - let _: u64 = uniform(&mut rng); + rng.sample::(Uniform); + rng.sample::(Uniform); + rng.sample::(Uniform); + rng.sample::(Uniform); + rng.sample::(Uniform); #[cfg(feature = "i128_support")] - let _: u128 = uniform(&mut rng); + rng.sample::(Uniform); } #[test] fn test_chars() { let mut rng = ::test::rng(); - let _ = codepoint(&mut rng); - let c = ascii_word_char(&mut rng); + let _ = rng.sample(Codepoint); + let c = rng.sample(AsciiWordChar); assert!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); - let word: String = iter(&mut rng).take(5).map(|rng| ascii_word_char(rng)).collect(); + let word: String = iter(&mut rng).take(5).map(|rng| rng.sample(AsciiWordChar)).collect(); assert_eq!(word.len(), 5); } #[test] fn test_f64() { - let mut r = thread_rng(); - let a: f64 = Rand::rand(&mut r, Uniform01); - let b = f64::rand(&mut r, Uniform01); + let mut rng = thread_rng(); + let a: f64 = rng.sample(Uniform01); + let b = rng.sample::(Uniform01); assert!(0.0 <= a && a < 1.0); assert!(0.0 <= b && b < 1.0); } @@ -303,10 +292,10 @@ mod tests { let mut rng = thread_rng(); for _ in 0..1_000 { // strict inequalities - let f = f64::rand(&mut rng, Open01); + let f: f64 = rng.sample(Open01); assert!(0.0 < f && f < 1.0); - let f = f32::rand(&mut rng, Open01); + let f: f32 = rng.sample(Open01); assert!(0.0 < f && f < 1.0); } } @@ -316,10 +305,10 @@ mod tests { let mut rng = thread_rng(); for _ in 0..1_000 { // strict inequalities - let f = f64::rand(&mut rng, Closed01); + let f: f64 = rng.sample(Closed01); assert!(0.0 <= f && f <= 1.0); - let f = f32::rand(&mut rng, Closed01); + let f: f32 = rng.sample(Closed01); assert!(0.0 <= f && f <= 1.0); } } diff --git a/src/iter.rs b/src/iter.rs index a819d33cdf7..1d44d2c9d0f 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -36,14 +36,14 @@ pub struct Iter<'a, R: Rng+?Sized+'a> { /// # Example /// /// ``` -/// use rand::{thread_rng, Rng, iter}; -/// use rand::distributions::{uniform, ascii_word_char}; +/// use rand::{thread_rng, Rng, Sample, iter}; +/// use rand::distributions::{Uniform, AsciiWordChar}; /// /// let mut rng = thread_rng(); -/// let x: Vec = iter(&mut rng).take(10).map(|rng| uniform(rng)).collect(); +/// let x: Vec = iter(&mut rng).take(10).map(|rng| rng.sample(Uniform)).collect(); /// println!("{:?}", x); /// -/// let w: String = iter(&mut rng).take(6).map(|rng| ascii_word_char(rng)).collect(); +/// let w: String = iter(&mut rng).take(6).map(|rng| rng.sample(AsciiWordChar)).collect(); /// println!("{}", w); /// ``` pub fn iter<'a, R: Rng+?Sized+'a>(rng: &'a mut R) -> Iter<'a, R> { @@ -159,8 +159,8 @@ impl<'a, R:?Sized+'a, U, F> Iterator for FlatMap<'a, R, U, F> #[cfg(test)] mod tests { - use {Rng, thread_rng, iter}; - use distributions::{uniform, ascii_word_char}; + use {Rng, Sample, thread_rng, iter}; + use distributions::{Uniform, AsciiWordChar}; #[test] fn test_iter() { @@ -168,10 +168,10 @@ mod tests { let x: Vec<()> = iter(&mut rng).take(10).map(|_| ()).collect(); assert_eq!(x.len(), 10); - let y: Vec = iter(&mut rng).take(10).map(|rng| uniform(rng)).collect(); + let y: Vec = iter(&mut rng).take(10).map(|rng| rng.sample(Uniform)).collect(); assert_eq!(y.len(), 10); let z: Vec = iter(&mut rng).take(10).flat_map(|rng| - vec![uniform(rng), uniform(rng)].into_iter()).collect(); + vec![rng.sample(Uniform), rng.sample(Uniform)].into_iter()).collect(); assert_eq!(z.len(), 20); let w: Vec = iter(&mut rng).take(10).flat_map(|_| vec![].into_iter()).collect(); assert_eq!(w.len(), 0); @@ -181,7 +181,7 @@ mod tests { fn test_dyn_dispatch() { let r: &mut Rng = &mut thread_rng(); - let x: String = iter(r).take(10).map(|rng| ascii_word_char(rng)).collect(); + let x: String = iter(r).take(10).map(|rng| rng.sample(AsciiWordChar)).collect(); assert_eq!(x.len(), 10); } } diff --git a/src/lib.rs b/src/lib.rs index a44d670a0c3..e60d3dde2e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,10 +86,10 @@ //! ``` //! //! ```rust -//! use rand::thread_rng; -//! use rand::distributions::{Rand, Uniform, Uniform01}; +//! use rand::{Sample, thread_rng}; +//! use rand::distributions::{Uniform, Uniform01}; //! let mut rng = thread_rng(); -//! let tuple = (f64::rand(&mut rng, Uniform01), u8::rand(&mut rng, Uniform)); +//! let tuple: (f64, u8) = (rng.sample(Uniform01), rng.sample(Uniform)); //! println!("{:?}", tuple) //! ``` //! @@ -111,18 +111,19 @@ //! and multiply this fraction by 4. //! //! ``` -//! use rand::distributions::{Rand, Range}; +//! use rand::{thread_rng, Sample}; +//! use rand::distributions::{Range}; //! //! fn main() { //! let between = Range::new(-1f64, 1.); -//! let mut rng = rand::thread_rng(); +//! let mut rng = thread_rng(); //! //! let total = 1_000_000; //! let mut in_circle = 0; //! //! for _ in 0..total { -//! let a = f64::rand(&mut rng, between); -//! let b = f64::rand(&mut rng, between); +//! let a = rng.sample(between); +//! let b = rng.sample(between); //! if a*a + b*b <= 1. { //! in_circle += 1; //! } @@ -153,8 +154,8 @@ //! [Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem //! //! ``` -//! use rand::Rng; -//! use rand::distributions::{Distribution, Range, uniform}; +//! use rand::{Rng, Sample}; +//! use rand::distributions::{Distribution, Range}; //! use rand::distributions::range::RangeInt; //! use rand::sequences::Choose; //! @@ -175,7 +176,7 @@ //! let open = game_host_open(car, choice, rng); //! //! // Shall we switch? -//! let switch = uniform(rng); +//! let switch = rng.gen(); //! if switch { //! choice = switch_door(choice, open); //! } @@ -424,8 +425,7 @@ pub trait Sample: Rng { /// } /// ``` fn gen_range(&mut self, low: T, high: T) -> T { - assert!(low < high, "Sample::gen_range called with low >= high"); - Range::new(low, high).sample(self) + Range::sample_single(low, high, self) } /// Construct an iterator on an `Rng`. @@ -462,9 +462,11 @@ pub struct StdRng { } impl Rng for StdRng { + #[inline] fn next_u32(&mut self) -> u32 { self.rng.next_u32() } + #[inline] fn next_u64(&mut self) -> u64 { self.rng.next_u64() } @@ -490,8 +492,7 @@ impl SeedFromRng for StdRng { #[cfg(test)] mod test { use {Rng, thread_rng, Sample, Error}; - use mock::MockAddRng; - use distributions::{uniform}; + use mock::MockAddRng; use distributions::{Uniform, Range, Exp}; use sequences::Shuffle; use std::iter::repeat; @@ -562,7 +563,7 @@ mod test { #[test] fn test_thread_rng() { let mut r = thread_rng(); - uniform::(&mut r); + r.sample::(Uniform); let mut v = [1, 1, 1]; v.shuffle(&mut r); let b: &[_] = &[1, 1, 1]; @@ -576,7 +577,7 @@ mod test { { let r = &mut rng as &mut Rng; r.next_u32(); - uniform::(r); + r.sample::(Uniform); let mut v = [1, 1, 1]; v[..].shuffle(r); let b: &[_] = &[1, 1, 1]; @@ -586,7 +587,7 @@ mod test { { let mut r = Box::new(rng) as Box; r.next_u32(); - uniform::(&mut r); + r.sample::(Uniform); let mut v = [1, 1, 1]; v[..].shuffle(&mut *r); let b: &[_] = &[1, 1, 1]; diff --git a/src/prng/isaac_word.rs b/src/prng/isaac_word.rs index 330656b3b8b..eb66826f618 100644 --- a/src/prng/isaac_word.rs +++ b/src/prng/isaac_word.rs @@ -33,10 +33,12 @@ type WordRngType = super::isaac64::Isaac64Rng; pub struct IsaacWordRng(WordRngType); impl Rng for IsaacWordRng { + #[inline] fn next_u32(&mut self) -> u32 { self.0.next_u32() } + #[inline] fn next_u64(&mut self) -> u64 { self.0.next_u64() } diff --git a/src/read.rs b/src/read.rs index 772d83e7223..c4a41bbbd12 100644 --- a/src/read.rs +++ b/src/read.rs @@ -26,11 +26,11 @@ use {Rng, Error, ErrorKind}; /// # Example /// /// ```rust -/// use rand::{ReadRng, distributions}; +/// use rand::{Rng, ReadRng, distributions}; /// /// let data = vec![1, 2, 3, 4, 5, 6, 7, 8]; /// let mut rng = ReadRng::new(&data[..]); -/// println!("{:x}", distributions::uniform::(&mut rng)); +/// println!("{:x}", rng.next_u32()); /// ``` #[derive(Debug)] // Do not derive Clone, because it could share the underlying reader diff --git a/src/reseeding.rs b/src/reseeding.rs index 5d95910825f..67e2543b0b3 100644 --- a/src/reseeding.rs +++ b/src/reseeding.rs @@ -11,14 +11,13 @@ //! A wrapper around another RNG that reseeds it after it //! generates a certain number of random bytes. -use core::cmp::max; use {Rng, SeedableRng, Error, ErrorKind}; #[cfg(feature="std")] use NewSeeded; /// How many bytes of entropy the underling RNG is allowed to generate /// before it is reseeded -const DEFAULT_GENERATION_THRESHOLD: u64 = 32 * 1024; +const DEFAULT_RESEEDING_THRESHOLD: i64 = 32 * 1024; /// A wrapper around any RNG which reseeds the underlying RNG after it /// has generated a certain number of random bytes. @@ -32,8 +31,8 @@ const DEFAULT_GENERATION_THRESHOLD: u64 = 32 * 1024; #[derive(Debug, Clone)] pub struct ReseedingRng> { rng: R, - generation_threshold: u64, - bytes_generated: u64, + threshold: i64, + bytes_until_reseed: i64, /// Controls the behaviour when reseeding the RNG. pub reseeder: Rsdr, } @@ -44,13 +43,14 @@ impl> ReseedingRng { /// # Arguments /// /// * `rng`: the random number generator to use. - /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG. + /// * `threshold`: the amount of generated bytes after which to reseed the RNG. /// * `reseeder`: the reseeding object to use. - pub fn new(rng: R, generation_threshold: u64, reseeder: Rsdr) -> ReseedingRng { + pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> ReseedingRng { + assert!(threshold <= ::core::i64::MAX as u64); ReseedingRng { rng: rng, - generation_threshold: generation_threshold, - bytes_generated: 0, + threshold: threshold as i64, + bytes_until_reseed: threshold as i64, reseeder: reseeder } } @@ -59,33 +59,31 @@ impl> ReseedingRng { /// generated exceed the threshold. /// /// On error, this may delay reseeding or not reseed at all. - pub fn reseed_if_necessary(&mut self) { - if self.bytes_generated >= self.generation_threshold { - let mut err_count = 0; - loop { - if let Err(e) = self.reseeder.reseed(&mut self.rng) { - // TODO: log? - if e.kind.should_wait() { - // Delay reseeding - let delay = max(self.generation_threshold >> 8, self.bytes_generated); - self.bytes_generated -= delay; - break; - } else if e.kind.should_retry() { - if err_count > 4 { // arbitrary limit - // TODO: log details & cause? - break; // give up trying to reseed - } - err_count += 1; - continue; // immediate retry - } else { + #[inline(never)] + pub fn reseed(&mut self) { + let mut err_count = 0; + loop { + if let Err(e) = self.reseeder.reseed(&mut self.rng) { + // TODO: log? + if e.kind.should_wait() { + // Delay reseeding + self.bytes_until_reseed = self.threshold >> 8; + break; + } else if e.kind.should_retry() { + if err_count > 4 { // arbitrary limit + // TODO: log details & cause? break; // give up trying to reseed } + err_count += 1; + continue; // immediate retry } else { - break; // no reseeding + break; // give up trying to reseed } + } else { + break; // no reseeding } - self.bytes_generated = 0; } + self.bytes_until_reseed = self.threshold; } /// Reseed the internal RNG if the number of bytes that have been /// generated exceed the threshold. @@ -93,67 +91,82 @@ impl> ReseedingRng { /// If reseeding fails, return an error with the original cause. Note that /// if the cause has a permanent failure, we report a transient error and /// skip reseeding. - pub fn try_reseed_if_necessary(&mut self) -> Result<(), Error> { - if self.bytes_generated >= self.generation_threshold { - if let Err(err) = self.reseeder.reseed(&mut self.rng) { - let newkind = match err.kind { - a @ ErrorKind::NotReady => a, - b @ ErrorKind::Transient => b, - _ => { - self.bytes_generated = 0; // skip reseeding - ErrorKind::Transient - } - }; - return Err(Error::with_cause(newkind, "reseeding failed", err)); - } - self.bytes_generated = 0; + #[inline(never)] + pub fn try_reseed(&mut self) -> Result<(), Error> { + if let Err(err) = self.reseeder.reseed(&mut self.rng) { + let newkind = match err.kind { + a @ ErrorKind::NotReady => a, + b @ ErrorKind::Transient => b, + _ => { + self.bytes_until_reseed = self.threshold; // skip reseeding + ErrorKind::Transient + } + }; + return Err(Error::with_cause(newkind, "reseeding failed", err)); } + self.bytes_until_reseed = self.threshold; Ok(()) } } impl> Rng for ReseedingRng { + #[inline] fn next_u32(&mut self) -> u32 { - self.reseed_if_necessary(); - self.bytes_generated += 4; - self.rng.next_u32() + let value = self.rng.next_u32(); + self.bytes_until_reseed -= 4; + if self.bytes_until_reseed <= 0 { + self.reseed(); + } + value } + #[inline] fn next_u64(&mut self) -> u64 { - self.reseed_if_necessary(); - self.bytes_generated += 8; - self.rng.next_u64() + let value = self.rng.next_u64(); + self.bytes_until_reseed -= 8; + if self.bytes_until_reseed <= 0 { + self.reseed(); + } + value } #[cfg(feature = "i128_support")] fn next_u128(&mut self) -> u128 { - self.reseed_if_necessary(); - self.bytes_generated += 16; - self.rng.next_u128() + let value = self.rng.next_u128(); + self.bytes_until_reseed -= 16; + if self.bytes_until_reseed <= 0 { + self.reseed(); + } + value } fn fill_bytes(&mut self, dest: &mut [u8]) { - self.reseed_if_necessary(); - self.bytes_generated += dest.len() as u64; self.rng.fill_bytes(dest); + self.bytes_until_reseed -= dest.len() as i64; + if self.bytes_until_reseed <= 0 { + self.reseed(); + } } fn try_fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.try_reseed_if_necessary()?; - self.bytes_generated += dest.len() as u64; - self.rng.try_fill(dest) + self.rng.try_fill(dest)?; + self.bytes_until_reseed -= dest.len() as i64; + if self.bytes_until_reseed <= 0 { + self.try_reseed()?; + } + Ok(()) } } impl> ReseedingRng { /// Create a new `ReseedingRng` from the given reseeder and - /// seed. This uses a default value for `generation_threshold`. + /// seed. This uses a default value for `threshold`. pub fn from_reseeder(rsdr: Rsdr, seed: ::Seed) -> ReseedingRng { ReseedingRng { rng: SeedableRng::from_seed(seed), - generation_threshold: DEFAULT_GENERATION_THRESHOLD, - bytes_generated: 0, + threshold: DEFAULT_RESEEDING_THRESHOLD, + bytes_until_reseed: DEFAULT_RESEEDING_THRESHOLD, reseeder: rsdr } } diff --git a/src/thread_local.rs b/src/thread_local.rs index 0d7348ec244..8e26358028c 100644 --- a/src/thread_local.rs +++ b/src/thread_local.rs @@ -13,11 +13,11 @@ use std::cell::RefCell; use std::rc::Rc; -use {Rng, StdRng, NewSeeded, Rand, Default, Error}; +use {Rng, StdRng, NewSeeded, Distribution, Default, Sample, Error}; use reseeding::{ReseedingRng, ReseedWithNew}; -const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768; +const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768*1024; type ReseedingStdRng = ReseedingRng; /// The thread-local RNG. @@ -27,10 +27,12 @@ pub struct ThreadRng { } impl Rng for ThreadRng { + #[inline] fn next_u32(&mut self) -> u32 { self.rng.borrow_mut().next_u32() } + #[inline] fn next_u64(&mut self) -> u64 { self.rng.borrow_mut().next_u64() } @@ -100,7 +102,7 @@ pub fn thread_rng() -> ThreadRng { /// Caching the thread local random number generator: /// /// ``` -/// use rand::{Rand, Default}; +/// use rand::{Sample}; /// /// let mut v = vec![1, 2, 3]; /// @@ -113,15 +115,12 @@ pub fn thread_rng() -> ThreadRng { /// let mut rng = rand::thread_rng(); /// /// for x in v.iter_mut() { -/// *x = Rand::rand(&mut rng, Default); +/// *x = rng.gen() /// } /// ``` -/// -/// Note that the above example uses `SampleDefault` which is a zero-sized -/// marker type. #[inline] -pub fn random>() -> T { - T::rand(&mut thread_rng(), Default) +pub fn random() -> T where Default: Distribution { + thread_rng().sample(Default) } /// Generates a random value using the thread-local random number generator. @@ -130,8 +129,8 @@ pub fn random>() -> T { /// distribution used. For example: /// /// ``` -/// use rand::random_with; -/// use rand::distributions::{Rand, Default, Uniform01, Closed01, Range}; +/// use rand::{Sample, random_with}; +/// use rand::distributions::{Default, Uniform01, Closed01, Range}; /// /// // identical to calling `random()`: /// let x: f64 = random_with(Default); @@ -150,9 +149,9 @@ pub fn random>() -> T { /// let mut rng = rand::thread_rng(); /// let range = Range::new(0.0, 2.0); /// // Do this bit many times: -/// let v = f64::rand(&mut rng, range); +/// let v = rng.sample(range); /// ``` #[inline] -pub fn random_with>(distribution: D) -> T { - T::rand(&mut thread_rng(), distribution) +pub fn random_with(distribution: D) -> T where D: Distribution { + thread_rng().sample(distribution) } diff --git a/src/utils.rs b/src/utils.rs index 406d721b565..e6ed5ecbf17 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -10,7 +10,7 @@ //! A collection of utility functions //! -//! This module exposes some utility functions used internally by the `Rand` +//! This module exposes some utility functions used internally by the `rand` //! crate. They are not the intended or most ergonomic way to use the library. //! //! The `FloatConversions` trait provides the building blocks to convert a @@ -271,7 +271,8 @@ float_impls! { f64, u64, 64, 52, 0xf_ffff_ffff_ffff, 1023, Rng::next_u64 } #[cfg(test)] mod tests { use super::FloatConversions; - use distributions::uniform; + use Sample; + use distributions::Uniform; #[test] fn closed_open01_edge_cases() { @@ -315,14 +316,14 @@ mod tests { // These constants happen to generate the lowest and highest floats in // the range. let mut rng = ::test::rng(); - let mut bits: u32 = uniform(&mut rng); + let mut bits: u32 = rng.sample(Uniform); bits = bits & 0x1ff; // 9 bits with no influence assert!((bits | 0).closed_open01_fixed() == 0.0); assert!((bits | 0xfffffe00).closed_open01_fixed() == 0.9999999); // 1 - 2^-23 - let mut bits: u64 = uniform(&mut rng); + let mut bits: u64 = rng.sample(Uniform); bits = bits & 0xfff; // 12 bits with no influence assert!((bits | 0).closed_open01_fixed() == 0.0); @@ -336,13 +337,13 @@ mod tests { // These constants happen to generate the lowest and highest floats in // the range. let mut rng = ::test::rng(); - let mut bits: u32 = uniform(&mut rng); + let mut bits: u32 = rng.sample(Uniform); bits = bits & 0x1ff; // 9 bits with no influence assert!((bits | 0).open_closed01_fixed() == 1.1920929e-7); // 2^-23 assert!((bits | 0xfffffe00).open_closed01_fixed() == 1.0); - let mut bits: u64 = uniform(&mut rng); + let mut bits: u64 = rng.sample(Uniform); bits = bits & 0xfff; // 12 bits with no influence assert!((bits | 0).open_closed01_fixed() == @@ -356,14 +357,14 @@ mod tests { // These constants happen to generate the lowest and highest floats in // the range. let mut rng = ::test::rng(); - let mut bits: u32 = uniform(&mut rng); + let mut bits: u32 = rng.sample(Uniform); bits = bits & 0x1ff; // 9 bits with no influence assert!((bits | 0).closed_open11_fixed() == -1.0); assert!((bits | 0xfffffe00).closed_open11_fixed() == 0.99999976); // 1 - 2^-22 - let mut bits: u64 = uniform(&mut rng); + let mut bits: u64 = rng.sample(Uniform); bits = bits & 0xfff; // 12 bits with no influence assert!((bits | 0).closed_open11_fixed() == -1.0);