@@ -94,32 +94,52 @@ impl Rand for u64 {
94
94
}
95
95
}
96
96
97
- impl Rand for f32 {
98
- /// A random `f32` in the range `[0, 1)`, using 24 bits of
99
- /// precision.
100
- #[ inline]
101
- fn rand < R : Rng > ( rng : & mut R ) -> f32 {
102
- // using any more than 24 bits will cause (e.g.) 0xffff_ffff
103
- // to correspond to 1 exactly, so we need to drop 8 to
104
- // guarantee the open end.
97
+ macro_rules! float_impls {
98
+ ( $mod_name: ident, $ty: ty, $mantissa_bits: expr, $method_name: ident, $ignored_bits: expr) => {
99
+ mod $mod_name {
100
+ use rand:: { Rand , Rng , Open01 , Closed01 } ;
105
101
106
- static SCALE : f32 = ( 1u32 << 24 ) as f32 ;
107
- ( rng. next_u32 ( ) >> 8 ) as f32 / SCALE
108
- }
109
- }
110
-
111
- impl Rand for f64 {
112
- /// A random `f64` in the range `[0, 1)`, using 53 bits of
113
- /// precision.
114
- #[ inline]
115
- fn rand < R : Rng > ( rng : & mut R ) -> f64 {
116
- // as for f32, but using more bits.
102
+ static SCALE : $ty = ( 1u64 << $mantissa_bits) as $ty;
117
103
118
- static SCALE : f64 = ( 1u64 << 53 ) as f64 ;
119
- ( rng. next_u64 ( ) >> 11 ) as f64 / SCALE
104
+ impl Rand for $ty {
105
+ /// Generate a floating point number in the half-open
106
+ /// interval `[0,1)`.
107
+ ///
108
+ /// See `Closed01` for the closed interval `[0,1]`,
109
+ /// and `Open01` for the open interval `(0,1)`.
110
+ #[ inline]
111
+ fn rand<R : Rng >( rng: & mut R ) -> $ty {
112
+ // using any more than `mantissa_bits` bits will
113
+ // cause (e.g.) 0xffff_ffff to correspond to 1
114
+ // exactly, so we need to drop some (8 for f32, 11
115
+ // for f64) to guarantee the open end.
116
+ ( rng. $method_name( ) >> $ignored_bits) as $ty / SCALE
117
+ }
118
+ }
119
+ impl Rand for Open01 <$ty> {
120
+ #[ inline]
121
+ fn rand<R : Rng >( rng: & mut R ) -> Open01 <$ty> {
122
+ // add a small amount (specifically 2 bits below
123
+ // the precision of f64/f32 at 1.0), so that small
124
+ // numbers are larger than 0, but large numbers
125
+ // aren't pushed to/above 1.
126
+ Open01 ( ( ( rng. $method_name( ) >> $ignored_bits) as $ty + 0.25 ) / SCALE )
127
+ }
128
+ }
129
+ impl Rand for Closed01 <$ty> {
130
+ #[ inline]
131
+ fn rand<R : Rng >( rng: & mut R ) -> Closed01 <$ty> {
132
+ // divide by the maximum value of the numerator to
133
+ // get a non-zero probability of getting exactly
134
+ // 1.0.
135
+ Closed01 ( ( rng. $method_name( ) >> $ignored_bits) as $ty / ( SCALE - 1.0 ) )
136
+ }
137
+ }
138
+ }
120
139
}
121
140
}
122
-
141
+ float_impls ! { f64_rand_impls, f64 , 53 , next_u64, 11 }
142
+ float_impls ! { f32_rand_impls, f32 , 24 , next_u32, 8 }
123
143
124
144
impl Rand for char {
125
145
#[ inline]
@@ -206,7 +226,10 @@ impl<T: Rand + 'static> Rand for @T {
206
226
207
227
#[ cfg( test) ]
208
228
mod tests {
209
- use rand:: Rng ;
229
+ use rand:: { Rng , task_rng, Open01 , Closed01 } ;
230
+ use iter:: range;
231
+ use option:: { None , Some } ;
232
+
210
233
struct ConstantRng ( u64 ) ;
211
234
impl Rng for ConstantRng {
212
235
fn next_u32 ( & mut self ) -> u32 {
@@ -216,9 +239,36 @@ mod tests {
216
239
* * self
217
240
}
218
241
}
242
+
219
243
fn floating_point_edge_cases ( ) {
220
244
// the test for exact equality is correct here.
221
245
assert ! ( ConstantRng ( 0xffff_ffff ) . gen :: <f32 >( ) != 1.0 )
222
246
assert ! ( ConstantRng ( 0xffff_ffff_ffff_ffff ) . gen :: <f64 >( ) != 1.0 )
223
247
}
248
+
249
+ fn rand_open ( ) {
250
+ // this is unlikely to catch an incorrect implementation that
251
+ // generates exactly 0 or 1, but it keeps it sane.
252
+ let mut rng = task_rng ( ) ;
253
+ for _ in range ( 0 , 1_000 ) {
254
+ // strict inequalities
255
+ let f = * rng. gen :: < Open01 < f64 > > ( ) ;
256
+ assert ! ( 0.0 < f && f < 1.0 ) ;
257
+
258
+ let f = * rng. gen :: < Open01 < f32 > > ( ) ;
259
+ assert ! ( 0.0 < f && f < 1.0 ) ;
260
+ }
261
+ }
262
+
263
+ fn rand_closed ( ) {
264
+ let mut rng = task_rng ( ) ;
265
+ for _ in range ( 0 , 1_000 ) {
266
+ // strict inequalities
267
+ let f = * rng. gen :: < Closed01 < f64 > > ( ) ;
268
+ assert ! ( 0.0 <= f && f <= 1.0 ) ;
269
+
270
+ let f = * rng. gen :: < Closed01 < f32 > > ( ) ;
271
+ assert ! ( 0.0 <= f && f <= 1.0 ) ;
272
+ }
273
+ }
224
274
}
0 commit comments