1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Generating numbers between two others.
13 // this is surprisingly complicated to be both generic & correct
19 use distributions::{Sample, IndependentSample};
21 /// Sample values uniformly between two bounds.
23 /// This gives a uniform distribution (assuming the RNG used to sample
24 /// it is itself uniform & the `SampleRange` implementation for the
25 /// given type is correct), even for edge cases like `low = 0u8`,
26 /// `high = 170u8`, for which a naive modulo operation would return
27 /// numbers less than 85 with double the probability to those greater
30 /// Types should attempt to sample in `[low, high)`, i.e., not
31 /// including `high`, but this may be very difficult. All the
32 /// primitive integer types satisfy this property, and the float types
33 /// normally satisfy it, but rounding may mean `high` can occur.
38 /// use std::rand::distributions::{IndependentSample, Range};
41 /// let between = Range::new(10u, 10000u);
42 /// let mut rng = std::rand::thread_rng();
44 /// for _ in range(0u, 1000) {
45 /// sum += between.ind_sample(&mut rng);
47 /// println!("{}", sum);
56 impl<X: SampleRange + PartialOrd> Range<X> {
57 /// Create a new `Range` instance that samples uniformly from
58 /// `[low, high)`. Panics if `low >= high`.
59 pub fn new(low: X, high: X) -> Range<X> {
60 assert!(low < high, "Range::new called with `low >= high`");
61 SampleRange::construct_range(low, high)
65 impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
67 fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
69 impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
70 fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
71 SampleRange::sample_range(self, rng)
75 /// The helper trait for types that have a sensible way to sample
76 /// uniformly between two values. This should not be used directly,
77 /// and is only to facilitate `Range`.
78 pub trait SampleRange {
79 /// Construct the `Range` object that `sample_range`
80 /// requires. This should not ever be called directly, only via
81 /// `Range::new`, which will check that `low < high`, so this
82 /// function doesn't have to repeat the check.
83 fn construct_range(low: Self, high: Self) -> Range<Self>;
85 /// Sample a value from the given `Range` with the given `Rng` as
86 /// a source of randomness.
87 fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self;
90 macro_rules! integer_impl {
91 ($ty:ty, $unsigned:ty) => {
92 impl SampleRange for $ty {
93 // we play free and fast with unsigned vs signed here
94 // (when $ty is signed), but that's fine, since the
95 // contract of this macro is for $ty and $unsigned to be
96 // "bit-equal", so casting between them is a no-op & a
99 fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
100 let range = high as $unsigned - low as $unsigned;
101 let unsigned_max: $unsigned = Int::max_value();
103 // this is the largest number that fits into $unsigned
104 // that `range` divides evenly, so, if we've sampled
105 // `n` uniformly from this region, then `n % range` is
106 // uniform in [0, range)
107 let zone = unsigned_max - unsigned_max % range;
112 accept_zone: zone as $ty
116 fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
119 let v = rng.gen::<$unsigned>();
120 // until we find something that fits into the
121 // region which r.range evenly divides (this will
122 // be uniformly distributed)
123 if v < r.accept_zone as $unsigned {
124 // and return it, with some adjustments
125 return r.low + (v % r.range as $unsigned) as $ty;
133 integer_impl! { i8, u8 }
134 integer_impl! { i16, u16 }
135 integer_impl! { i32, u32 }
136 integer_impl! { i64, u64 }
137 integer_impl! { int, uint }
138 integer_impl! { u8, u8 }
139 integer_impl! { u16, u16 }
140 integer_impl! { u32, u32 }
141 integer_impl! { u64, u64 }
142 integer_impl! { uint, uint }
144 macro_rules! float_impl {
146 impl SampleRange for $ty {
147 fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
151 accept_zone: 0.0 // unused
154 fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
155 r.low + r.range * rng.gen()
167 use std::prelude::v1::*;
168 use distributions::{Sample, IndependentSample};
173 fn test_range_bad_limits_equal() {
174 Range::new(10i, 10i);
178 fn test_range_bad_limits_flipped() {
184 let mut rng = ::test::rng();
188 let v: &[($ty, $ty)] = &[(0, 10),
190 (Int::min_value(), Int::max_value())];
191 for &(low, high) in v.iter() {
192 let mut sampler: Range<$ty> = Range::new(low, high);
193 for _ in range(0u, 1000) {
194 let v = sampler.sample(&mut rng);
195 assert!(low <= v && v < high);
196 let v = sampler.ind_sample(&mut rng);
197 assert!(low <= v && v < high);
203 t!(i8, i16, i32, i64, int,
204 u8, u16, u32, u64, uint)
209 let mut rng = ::test::rng();
213 let v: &[($ty, $ty)] = &[(0.0, 100.0),
217 for &(low, high) in v.iter() {
218 let mut sampler: Range<$ty> = Range::new(low, high);
219 for _ in range(0u, 1000) {
220 let v = sampler.sample(&mut rng);
221 assert!(low <= v && v < high);
222 let v = sampler.ind_sample(&mut rng);
223 assert!(low <= v && v < high);