@@ -14,6 +14,32 @@ use core::mem;
14
14
use Rng ;
15
15
use distributions:: { Distribution , Uniform } ;
16
16
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
+ /// ```
17
43
#[ derive( Clone , Copy , Debug ) ]
18
44
pub struct HighPrecision01 ;
19
45
@@ -56,7 +82,7 @@ macro_rules! float_impls {
56
82
/// use rand::distributions::Uniform;
57
83
///
58
84
/// let val: f32 = SmallRng::new().sample(Uniform);
59
- /// println!("f32 from ( 0,1): {}", val);
85
+ /// println!("f32 from [ 0,1): {}", val);
60
86
/// ```
61
87
fn sample<R : Rng + ?Sized >( & self , rng: & mut R ) -> $ty {
62
88
const EPSILON : $ty = 1.0 / ( 1u64 << $fraction_bits) as $ty;
@@ -69,10 +95,10 @@ macro_rules! float_impls {
69
95
}
70
96
71
97
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.
74
100
///
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
76
102
/// of an RNG for a `f32`, instead of only 23, the number of bits
77
103
/// that fit in a floats fraction (or 64 instead of 52 bits for a
78
104
/// `f64`).
@@ -83,7 +109,7 @@ macro_rules! float_impls {
83
109
/// use rand::distributions::HighPrecision01;
84
110
///
85
111
/// let val: f32 = SmallRng::new().sample(HighPrecision01);
86
- /// println!("f32 from ( 0,1): {}", val);
112
+ /// println!("f32 from [ 0,1): {}", val);
87
113
/// ```
88
114
///
89
115
/// # Algorithm
@@ -135,6 +161,7 @@ float_impls! { f64, u64, 52, 1023, next_u64 }
135
161
mod tests {
136
162
use Rng ;
137
163
use mock:: StepRng ;
164
+ use super :: HighPrecision01 ;
138
165
139
166
const EPSILON32 : f32 = :: core:: f32:: EPSILON ;
140
167
const EPSILON64 : f64 = :: core:: f64:: EPSILON ;
@@ -157,4 +184,18 @@ mod tests {
157
184
assert_eq ! ( max. gen :: <f32 >( ) , 1.0 - EPSILON32 / 2.0 ) ;
158
185
assert_eq ! ( max. gen :: <f64 >( ) , 1.0 - EPSILON64 / 2.0 ) ;
159
186
}
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
+ }
160
201
}
0 commit comments