From b25b6572ccd69fe4a0575f8397a535d941af231e Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sun, 9 Jun 2019 19:04:39 -0700 Subject: [PATCH] Implement Distribution for Range(Inclusive) --- src/distributions/uniform.rs | 31 +++++++++++++++++++++++++++++-- src/lib.rs | 5 +++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs index 48d6f3f64f8..400c8442c9f 100644 --- a/src/distributions/uniform.rs +++ b/src/distributions/uniform.rs @@ -111,6 +111,7 @@ use std::time::Duration; #[cfg(not(feature = "std"))] use core::time::Duration; +use core::ops::{Range, RangeInclusive}; use crate::Rng; use crate::distributions::Distribution; @@ -147,6 +148,9 @@ use packed_simd::*; /// `Uniform::new(low, high)`, i.e., excluding `high`. In particular care must /// be taken to ensure that rounding never results values `< low` or `>= high`. /// +/// Range expressions like `0..10` can be used as a `Uniform` distribution, +/// but are less efficient if multiple samples are taken. +/// /// # Example /// /// ``` @@ -278,18 +282,30 @@ pub trait UniformSampler: Sized { } } -impl From<::core::ops::Range> for Uniform { +impl From> for Uniform { fn from(r: ::core::ops::Range) -> Uniform { Uniform::new(r.start, r.end) } } -impl From<::core::ops::RangeInclusive> for Uniform { +impl From> for Uniform { fn from(r: ::core::ops::RangeInclusive) -> Uniform { Uniform::new_inclusive(r.start(), r.end()) } } +impl Distribution for Range { + fn sample(&self, rng: &mut R) -> T { + T::Sampler::sample_single(&self.start, &self.end, rng) + } +} + +impl Distribution for RangeInclusive { + fn sample(&self, rng: &mut R) -> T { + T::Sampler::sample_single_inclusive(self.start(), self.end(), rng) + } +} + /// Helper trait similar to [`Borrow`] but implemented /// only for SampleUniform and references to SampleUniform in /// order to resolve ambiguity issues. @@ -1274,6 +1290,17 @@ mod tests { assert_eq!(r.inner.scale, 5.0); } + #[test] + fn test_std_range_distribution() { + let mut rng = crate::test::rng(474); + for _ in 0..100 { + let x = rng.sample(0..10); + assert!(x >= 0 && x < 10); + let x = rng.sample(0..=10); + assert!(x >= 0 && x <= 10); + } + } + #[test] fn test_uniform_from_std_range_inclusive() { let r = Uniform::from(2u32..=6); diff --git a/src/lib.rs b/src/lib.rs index 31f0169e1ae..b4de455ac4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -227,9 +227,10 @@ pub trait Rng: RngCore { /// use rand::distributions::Uniform; /// /// let mut rng = thread_rng(); - /// let x = rng.sample(Uniform::new(10u32, 15)); + /// let x = rng.sample(10u32..15); /// // Type annotation requires two types, the type and distribution; the - /// // distribution can be inferred. + /// // distribution can be inferred. `Uniform` is more efficient than the + /// // above range syntax if multiple samples are taken. /// let y = rng.sample::(Uniform::new(10, 15)); /// ``` fn sample>(&mut self, distr: D) -> T {