@@ -14,6 +14,30 @@ use core::mem;
14
14
use Rng ;
15
15
use distributions:: { Distribution , Standard } ;
16
16
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
+
17
41
pub ( crate ) trait IntoFloat {
18
42
type F ;
19
43
@@ -29,8 +53,7 @@ pub(crate) trait IntoFloat {
29
53
}
30
54
31
55
macro_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) => {
34
57
impl IntoFloat for $uty {
35
58
type F = $ty;
36
59
#[ inline( always) ]
@@ -43,26 +66,42 @@ macro_rules! float_impls {
43
66
}
44
67
45
68
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.
48
69
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.
49
87
const EPSILON : $ty = 1.0 / ( 1u64 << $fraction_bits) as $ty;
50
88
let float_size = mem:: size_of:: <$ty>( ) * 8 ;
51
89
52
- let value = rng. $next_u ( ) ;
90
+ let value: $uty = rng. gen ( ) ;
53
91
let fraction = value >> ( float_size - $fraction_bits) ;
54
92
fraction. into_float_with_exponent( 0 ) - ( 1.0 - EPSILON / 2.0 )
55
93
}
56
94
}
57
95
}
58
96
}
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 }
61
99
62
100
63
101
#[ cfg( test) ]
64
102
mod tests {
65
103
use Rng ;
104
+ use distributions:: Open01 ;
66
105
use mock:: StepRng ;
67
106
68
107
const EPSILON32 : f32 = :: core:: f32:: EPSILON ;
@@ -71,19 +110,34 @@ mod tests {
71
110
#[ test]
72
111
fn floating_point_edge_cases ( ) {
73
112
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 ) ;
76
115
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 ) ;
80
118
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 ) ;
84
121
85
122
let mut max = StepRng :: new ( !0 , 0 ) ;
86
123
assert_eq ! ( max. gen :: <f32 >( ) , 1.0 - EPSILON32 / 2.0 ) ;
87
124
assert_eq ! ( max. gen :: <f64 >( ) , 1.0 - EPSILON64 / 2.0 ) ;
88
125
}
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
+ }
89
143
}
0 commit comments