use std::num::Wrapping as w;
use Rng;
use distributions::{Sample, IndependentSample};
#[derive(Copy)]
pub struct Range<X> {
low: X,
range: X,
accept_zone: X
}
impl<X: SampleRange + PartialOrd> Range<X> {
pub fn new(low: X, high: X) -> Range<X> {
assert!(low < high, "Range::new called with `low >= high`");
SampleRange::construct_range(low, high)
}
}
impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
#[inline]
fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}
impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
SampleRange::sample_range(self, rng)
}
}
pub trait SampleRange {
fn construct_range(low: Self, high: Self) -> Range<Self>;
fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self;
}
macro_rules! integer_impl {
($ty:ty, $unsigned:ident) => {
impl SampleRange for $ty {
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
let range = (w(high as $unsigned) - w(low as $unsigned)).0;
let unsigned_max: $unsigned = ::std::$unsigned::MAX;
let zone = unsigned_max - unsigned_max % range;
Range {
low: low,
range: range as $ty,
accept_zone: zone as $ty
}
}
#[inline]
fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
loop {
let v = rng.gen::<$unsigned>();
if v < r.accept_zone as $unsigned {
return (w(r.low) + w((v % r.range as $unsigned) as $ty)).0;
}
}
}
}
}
}
integer_impl! { i8, u8 }
integer_impl! { i16, u16 }
integer_impl! { i32, u32 }
integer_impl! { i64, u64 }
integer_impl! { isize, usize }
integer_impl! { u8, u8 }
integer_impl! { u16, u16 }
integer_impl! { u32, u32 }
integer_impl! { u64, u64 }
integer_impl! { usize, usize }
macro_rules! float_impl {
($ty:ty) => {
impl SampleRange for $ty {
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
Range {
low: low,
range: high - low,
accept_zone: 0.0 }
}
fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
r.low + r.range * rng.gen::<$ty>()
}
}
}
}
float_impl! { f32 }
float_impl! { f64 }
#[cfg(test)]
mod tests {
use distributions::{Sample, IndependentSample};
use super::Range as Range;
#[should_panic]
#[test]
fn test_range_bad_limits_equal() {
Range::new(10, 10);
}
#[should_panic]
#[test]
fn test_range_bad_limits_flipped() {
Range::new(10, 5);
}
#[test]
fn test_integers() {
let mut rng = ::test::rng();
macro_rules! t {
($($ty:ident),*) => {{
$(
let v: &[($ty, $ty)] = &[(0, 10),
(10, 127),
(::std::$ty::MIN, ::std::$ty::MAX)];
for &(low, high) in v.iter() {
let mut sampler: Range<$ty> = Range::new(low, high);
for _ in 0..1000 {
let v = sampler.sample(&mut rng);
assert!(low <= v && v < high);
let v = sampler.ind_sample(&mut rng);
assert!(low <= v && v < high);
}
}
)*
}}
}
t!(i8, i16, i32, i64, isize,
u8, u16, u32, u64, usize)
}
#[test]
fn test_floats() {
let mut rng = ::test::rng();
macro_rules! t {
($($ty:ty),*) => {{
$(
let v: &[($ty, $ty)] = &[(0.0, 100.0),
(-1e35, -1e25),
(1e-35, 1e-25),
(-1e35, 1e35)];
for &(low, high) in v.iter() {
let mut sampler: Range<$ty> = Range::new(low, high);
for _ in 0..1000 {
let v = sampler.sample(&mut rng);
assert!(low <= v && v < high);
let v = sampler.ind_sample(&mut rng);
assert!(low <= v && v < high);
}
}
)*
}}
}
t!(f32, f64)
}
}