@@ -95,23 +95,28 @@ impl Rand for u64 {
95
95
}
96
96
97
97
impl Rand for f32 {
98
- /// A random `f32` in the range `[0, 1)`.
98
+ /// A random `f32` in the range `[0, 1)`, using 24 bits of
99
+ /// precision.
99
100
#[ inline]
100
101
fn rand < R : Rng > ( rng : & mut R ) -> f32 {
101
- // weird, but this is the easiest way to get 2**32
102
- static SCALE : f32 = 2.0 * ( 1u32 << 31 ) as f32 ;
103
- rng. next_u32 ( ) as f32 / SCALE
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.
105
+
106
+ static SCALE : f32 = ( 1u32 << 24 ) as f32 ;
107
+ ( rng. next_u32 ( ) >> 8 ) as f32 / SCALE
104
108
}
105
109
}
106
110
107
111
impl Rand for f64 {
108
- /// A random `f64` in the range `[0, 1)`.
112
+ /// A random `f64` in the range `[0, 1)`, using 53 bits of
113
+ /// precision.
109
114
#[ inline]
110
115
fn rand < R : Rng > ( rng : & mut R ) -> f64 {
111
- // weird, but this is the easiest way to get 2**64
112
- static SCALE : f64 = 2.0 * ( 1u64 << 63 ) as f64 ;
116
+ // as for f32, but using more bits.
113
117
114
- rng. next_u64 ( ) as f64 / SCALE
118
+ static SCALE : f64 = ( 1u64 << 53 ) as f64 ;
119
+ ( rng. next_u64 ( ) >> 11 ) as f64 / SCALE
115
120
}
116
121
}
117
122
@@ -198,3 +203,19 @@ impl<T: Rand + 'static> Rand for @T {
198
203
#[ inline]
199
204
fn rand < R : Rng > ( rng : & mut R ) -> @T { @rng. gen ( ) }
200
205
}
206
+
207
+ #[ cfg( test) ]
208
+ mod tests {
209
+ use rand:: Rng ;
210
+ struct ConstantRng ( u64 ) ;
211
+ impl Rng for ConstantRng {
212
+ fn next_u64 ( & mut self ) -> u64 {
213
+ * * self
214
+ }
215
+ }
216
+ fn floating_point_edge_cases ( ) {
217
+ // the test for exact equality is correct here.
218
+ assert ! ( ConstantRng ( 0xffff_ffff ) . gen :: <f32 >( ) != 1.0 )
219
+ assert ! ( ConstantRng ( 0xffff_ffff_ffff_ffff ) . gen :: <f64 >( ) != 1.0 )
220
+ }
221
+ }
0 commit comments