Skip to content

Commit

Permalink
Improve documentation and add test
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Mar 18, 2018
1 parent 95865cf commit 8cd8a5f
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 6 deletions.
51 changes: 46 additions & 5 deletions src/distributions/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,32 @@ use core::mem;
use Rng;
use distributions::{Distribution, Uniform};

/// Generate a floating point number in the half-open interval `[0, 1)` with a
/// uniform distribution.
///
/// This is different from `Uniform` in that it uses all 32 bits of an RNG for a
/// `f32`, instead of only 23, the number of bits that fit in a floats fraction
/// (or 64 instead of 52 bits for a `f64`).
///
/// The smallest interval between values that can be generated is 2^-32
/// (2.3283064e-10) for `f32`, and 2^-64 (5.421010862427522e-20) for `f64`.
/// But this interval increases further away from zero because of limitations of
/// the floating point format. Close to 1.0 the interval is 2^-24 (5.9604645e-8)
/// for `f32`, and 2^-53 (1,1102230246251565) for `f64`. Compare this with
/// `Uniform`, which has a fixed interval of 2^23 and 2^-52 respectively.
///
/// Note: in the future this may change to request even more bits from the RNG
/// if the value gets very close to 0.0, so it always has as many digits of
/// precision as the float can represent.
///
/// # Example
/// ```rust
/// use rand::{NewRng, SmallRng, Rng};
/// use rand::distributions::HighPrecision01;
///
/// let val: f32 = SmallRng::new().sample(HighPrecision01);
/// println!("f32 from [0,1): {}", val);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct HighPrecision01;

Expand Down Expand Up @@ -56,7 +82,7 @@ macro_rules! float_impls {
/// use rand::distributions::Uniform;
///
/// let val: f32 = SmallRng::new().sample(Uniform);
/// println!("f32 from (0,1): {}", val);
/// println!("f32 from [0,1): {}", val);
/// ```
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty {
const EPSILON: $ty = 1.0 / (1u64 << $fraction_bits) as $ty;
Expand All @@ -69,10 +95,10 @@ macro_rules! float_impls {
}

impl Distribution<$ty> for HighPrecision01 {
/// Generate a floating point number in the open interval `(0, 1)`
/// (not including either endpoint) with a uniform distribution.
/// Generate a floating point number in the half-open interval
/// `[0, 1)` with a uniform distribution.
///
/// This is different from `Uniform` in that it it uses all 32 bits
/// This is different from `Uniform` in that it uses all 32 bits
/// of an RNG for a `f32`, instead of only 23, the number of bits
/// that fit in a floats fraction (or 64 instead of 52 bits for a
/// `f64`).
Expand All @@ -83,7 +109,7 @@ macro_rules! float_impls {
/// use rand::distributions::HighPrecision01;
///
/// let val: f32 = SmallRng::new().sample(HighPrecision01);
/// println!("f32 from (0,1): {}", val);
/// println!("f32 from [0,1): {}", val);
/// ```
///
/// # Algorithm
Expand Down Expand Up @@ -135,6 +161,7 @@ float_impls! { f64, u64, 52, 1023, next_u64 }
mod tests {
use Rng;
use mock::StepRng;
use super::HighPrecision01;

const EPSILON32: f32 = ::core::f32::EPSILON;
const EPSILON64: f64 = ::core::f64::EPSILON;
Expand All @@ -157,4 +184,18 @@ mod tests {
assert_eq!(max.gen::<f32>(), 1.0 - EPSILON32 / 2.0);
assert_eq!(max.gen::<f64>(), 1.0 - EPSILON64 / 2.0);
}

#[test]
fn high_precision_01_edge_cases() {
// Test that the distribution is a half-open range over [0,1).
// These constants happen to generate the lowest and highest floats in
// the range.
let mut zeros = StepRng::new(0, 0);
assert_eq!(zeros.sample::<f32, _>(HighPrecision01), 0.0);
assert_eq!(zeros.sample::<f64, _>(HighPrecision01), 0.0);

let mut ones = StepRng::new(0xffff_ffff_ffff_ffff, 0);
assert_eq!(ones.sample::<f32, _>(HighPrecision01), 0.99999994);
assert_eq!(ones.sample::<f64, _>(HighPrecision01), 0.9999999999999999);
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ pub trait Rng: RngCore {
n <= 1 || self.gen_range(0, n) == 0
}

/// Return a bool with a `p` probability of being true.
/// Return a bool with a probability `p` of being true.
///
/// # Example
///
Expand Down

0 comments on commit 8cd8a5f

Please sign in to comment.