@@ -14,6 +14,30 @@ use core::mem;
1414use Rng ;
1515use distributions:: { Distribution , Standard } ;
1616
17+ /// A distribution to sample floating point numbers uniformly in the open
18+ /// interval `(0, 1)`, i.e. not including either endpoint.
19+ ///
20+ /// All values that can be generated are of the form `n * ε + ε/2`. For `f32`
21+ /// the 22 most significant random bits of an `u32` are used, for `f64` 52 from
22+ /// an `u64`. The conversion uses a transmute-based method.
23+ ///
24+ /// To sample from the half-open range `[0, 1)` instead, use the [`Standard`]
25+ /// distribution.
26+ ///
27+ /// # Example
28+ /// ```rust
29+ /// use rand::{thread_rng, Rng};
30+ /// use rand::distributions::Open01;
31+ ///
32+ /// let val: f32 = thread_rng().sample(Open01);
33+ /// println!("f32 from (0, 1): {}", val);
34+ /// ```
35+ ///
36+ /// [`Standard`]: struct.Standard.html
37+ #[ derive( Clone , Copy , Debug ) ]
38+ pub struct Open01 ;
39+
40+
1741pub ( crate ) trait IntoFloat {
1842 type F ;
1943
@@ -29,8 +53,7 @@ pub(crate) trait IntoFloat {
2953}
3054
3155macro_rules! float_impls {
32- ( $ty: ty, $uty: ty, $fraction_bits: expr, $exponent_bias: expr,
33- $next_u: ident) => {
56+ ( $ty: ty, $uty: ty, $fraction_bits: expr, $exponent_bias: expr) => {
3457 impl IntoFloat for $uty {
3558 type F = $ty;
3659 #[ inline( always) ]
@@ -43,26 +66,42 @@ macro_rules! float_impls {
4366 }
4467
4568 impl Distribution <$ty> for Standard {
46- /// Generate a floating point number in the open interval `(0, 1)`
47- /// (not including either endpoint) with a uniform distribution.
4869 fn sample<R : Rng + ?Sized >( & self , rng: & mut R ) -> $ty {
70+ // Multiply-based method; 24/53 random bits; [0, 1) interval.
71+ // We use the most significant bits because for simple RNGs
72+ // those are usually more random.
73+ let float_size = mem:: size_of:: <$ty>( ) * 8 ;
74+ let precision = $fraction_bits + 1 ;
75+ let scale = 1.0 / ( ( 1 as $uty << precision) as $ty) ;
76+
77+ let value: $uty = rng. gen ( ) ;
78+ scale * ( value >> ( float_size - precision) ) as $ty
79+ }
80+ }
81+
82+ impl Distribution <$ty> for Open01 {
83+ fn sample<R : Rng + ?Sized >( & self , rng: & mut R ) -> $ty {
84+ // Transmute-based method; 23/52 random bits; (0, 1) interval.
85+ // We use the most significant bits because for simple RNGs
86+ // those are usually more random.
4987 const EPSILON : $ty = 1.0 / ( 1u64 << $fraction_bits) as $ty;
5088 let float_size = mem:: size_of:: <$ty>( ) * 8 ;
5189
52- let value = rng. $next_u ( ) ;
90+ let value: $uty = rng. gen ( ) ;
5391 let fraction = value >> ( float_size - $fraction_bits) ;
5492 fraction. into_float_with_exponent( 0 ) - ( 1.0 - EPSILON / 2.0 )
5593 }
5694 }
5795 }
5896}
59- float_impls ! { f32 , u32 , 23 , 127 , next_u32 }
60- float_impls ! { f64 , u64 , 52 , 1023 , next_u64 }
97+ float_impls ! { f32 , u32 , 23 , 127 }
98+ float_impls ! { f64 , u64 , 52 , 1023 }
6199
62100
63101#[ cfg( test) ]
64102mod tests {
65103 use Rng ;
104+ use distributions:: Open01 ;
66105 use mock:: StepRng ;
67106
68107 const EPSILON32 : f32 = :: core:: f32:: EPSILON ;
@@ -71,19 +110,34 @@ mod tests {
71110 #[ test]
72111 fn floating_point_edge_cases ( ) {
73112 let mut zeros = StepRng :: new ( 0 , 0 ) ;
74- assert_eq ! ( zeros. gen :: <f32 >( ) , 0.0 + EPSILON32 / 2.0 ) ;
75- assert_eq ! ( zeros. gen :: <f64 >( ) , 0.0 + EPSILON64 / 2.0 ) ;
113+ assert_eq ! ( zeros. gen :: <f32 >( ) , 0.0 ) ;
114+ assert_eq ! ( zeros. gen :: <f64 >( ) , 0.0 ) ;
76115
77- let mut one = StepRng :: new ( 1 << 9 , 0 ) ;
78- let one32 = one. gen :: < f32 > ( ) ;
79- assert ! ( EPSILON32 < one32 && one32 < EPSILON32 * 2.0 ) ;
116+ let mut one32 = StepRng :: new ( 1 << 8 , 0 ) ;
117+ assert_eq ! ( one32. gen :: <f32 >( ) , EPSILON32 / 2.0 ) ;
80118
81- let mut one = StepRng :: new ( 1 << 12 , 0 ) ;
82- let one64 = one. gen :: < f64 > ( ) ;
83- assert ! ( EPSILON64 < one64 && one64 < EPSILON64 * 2.0 ) ;
119+ let mut one64 = StepRng :: new ( 1 << 11 , 0 ) ;
120+ assert_eq ! ( one64. gen :: <f64 >( ) , EPSILON64 / 2.0 ) ;
84121
85122 let mut max = StepRng :: new ( !0 , 0 ) ;
86123 assert_eq ! ( max. gen :: <f32 >( ) , 1.0 - EPSILON32 / 2.0 ) ;
87124 assert_eq ! ( max. gen :: <f64 >( ) , 1.0 - EPSILON64 / 2.0 ) ;
88125 }
126+
127+ #[ test]
128+ fn open01_edge_cases ( ) {
129+ let mut zeros = StepRng :: new ( 0 , 0 ) ;
130+ assert_eq ! ( zeros. sample:: <f32 , _>( Open01 ) , 0.0 + EPSILON32 / 2.0 ) ;
131+ assert_eq ! ( zeros. sample:: <f64 , _>( Open01 ) , 0.0 + EPSILON64 / 2.0 ) ;
132+
133+ let mut one32 = StepRng :: new ( 1 << 9 , 0 ) ;
134+ assert_eq ! ( one32. sample:: <f32 , _>( Open01 ) , EPSILON32 / 2.0 * 3.0 ) ;
135+
136+ let mut one64 = StepRng :: new ( 1 << 12 , 0 ) ;
137+ assert_eq ! ( one64. sample:: <f64 , _>( Open01 ) , EPSILON64 / 2.0 * 3.0 ) ;
138+
139+ let mut max = StepRng :: new ( !0 , 0 ) ;
140+ assert_eq ! ( max. sample:: <f32 , _>( Open01 ) , 1.0 - EPSILON32 / 2.0 ) ;
141+ assert_eq ! ( max. sample:: <f64 , _>( Open01 ) , 1.0 - EPSILON64 / 2.0 ) ;
142+ }
89143}
0 commit comments