Skip to content

Commit 8cd8a5f

Browse files
committed
Improve documentation and add test
1 parent 95865cf commit 8cd8a5f

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

src/distributions/float.rs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,32 @@ use core::mem;
1414
use Rng;
1515
use distributions::{Distribution, Uniform};
1616

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

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

7197
impl Distribution<$ty> for HighPrecision01 {
72-
/// Generate a floating point number in the open interval `(0, 1)`
73-
/// (not including either endpoint) with a uniform distribution.
98+
/// Generate a floating point number in the half-open interval
99+
/// `[0, 1)` with a uniform distribution.
74100
///
75-
/// This is different from `Uniform` in that it it uses all 32 bits
101+
/// This is different from `Uniform` in that it uses all 32 bits
76102
/// of an RNG for a `f32`, instead of only 23, the number of bits
77103
/// that fit in a floats fraction (or 64 instead of 52 bits for a
78104
/// `f64`).
@@ -83,7 +109,7 @@ macro_rules! float_impls {
83109
/// use rand::distributions::HighPrecision01;
84110
///
85111
/// let val: f32 = SmallRng::new().sample(HighPrecision01);
86-
/// println!("f32 from (0,1): {}", val);
112+
/// println!("f32 from [0,1): {}", val);
87113
/// ```
88114
///
89115
/// # Algorithm
@@ -135,6 +161,7 @@ float_impls! { f64, u64, 52, 1023, next_u64 }
135161
mod tests {
136162
use Rng;
137163
use mock::StepRng;
164+
use super::HighPrecision01;
138165

139166
const EPSILON32: f32 = ::core::f32::EPSILON;
140167
const EPSILON64: f64 = ::core::f64::EPSILON;
@@ -157,4 +184,18 @@ mod tests {
157184
assert_eq!(max.gen::<f32>(), 1.0 - EPSILON32 / 2.0);
158185
assert_eq!(max.gen::<f64>(), 1.0 - EPSILON64 / 2.0);
159186
}
187+
188+
#[test]
189+
fn high_precision_01_edge_cases() {
190+
// Test that the distribution is a half-open range over [0,1).
191+
// These constants happen to generate the lowest and highest floats in
192+
// the range.
193+
let mut zeros = StepRng::new(0, 0);
194+
assert_eq!(zeros.sample::<f32, _>(HighPrecision01), 0.0);
195+
assert_eq!(zeros.sample::<f64, _>(HighPrecision01), 0.0);
196+
197+
let mut ones = StepRng::new(0xffff_ffff_ffff_ffff, 0);
198+
assert_eq!(ones.sample::<f32, _>(HighPrecision01), 0.99999994);
199+
assert_eq!(ones.sample::<f64, _>(HighPrecision01), 0.9999999999999999);
200+
}
160201
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ pub trait Rng: RngCore {
539539
n <= 1 || self.gen_range(0, n) == 0
540540
}
541541

542-
/// Return a bool with a `p` probability of being true.
542+
/// Return a bool with a probability `p` of being true.
543543
///
544544
/// # Example
545545
///

0 commit comments

Comments
 (0)