diff options
| author | Huon Wilson <dbau.pp+github@gmail.com> | 2013-10-09 02:09:33 +1100 |
|---|---|---|
| committer | Huon Wilson <dbau.pp+github@gmail.com> | 2013-10-09 22:22:43 +1100 |
| commit | 38732c4b5cf778cb1b441bfc4290b3e3524b80c2 (patch) | |
| tree | a1577c0a69f15b8ffc3a06ddd2dcdd773973331d | |
| parent | a836f13dc0c2c636fd00b77d05f50a00cc3a7c55 (diff) | |
| download | rust-38732c4b5cf778cb1b441bfc4290b3e3524b80c2.tar.gz rust-38732c4b5cf778cb1b441bfc4290b3e3524b80c2.zip | |
std::rand: Correct the implementation of Rand for f32 & f64.
| -rw-r--r-- | src/libstd/rand/rand_impls.rs | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/src/libstd/rand/rand_impls.rs b/src/libstd/rand/rand_impls.rs index 976eea7191a..8ad0bd9e297 100644 --- a/src/libstd/rand/rand_impls.rs +++ b/src/libstd/rand/rand_impls.rs @@ -95,23 +95,28 @@ impl Rand for u64 { } impl Rand for f32 { - /// A random `f32` in the range `[0, 1)`. + /// A random `f32` in the range `[0, 1)`, using 24 bits of + /// precision. #[inline] fn rand<R: Rng>(rng: &mut R) -> f32 { - // weird, but this is the easiest way to get 2**32 - static SCALE: f32 = 2.0 * (1u32 << 31) as f32; - rng.next_u32() as f32 / SCALE + // using any more than 24 bits will cause (e.g.) 0xffff_ffff + // to correspond to 1 exactly, so we need to drop 8 to + // guarantee the open end. + + static SCALE: f32 = (1u32 << 24) as f32; + (rng.next_u32() >> 8) as f32 / SCALE } } impl Rand for f64 { - /// A random `f64` in the range `[0, 1)`. + /// A random `f64` in the range `[0, 1)`, using 53 bits of + /// precision. #[inline] fn rand<R: Rng>(rng: &mut R) -> f64 { - // weird, but this is the easiest way to get 2**64 - static SCALE: f64 = 2.0 * (1u64 << 63) as f64; + // as for f32, but using more bits. - rng.next_u64() as f64 / SCALE + static SCALE: f64 = (1u64 << 53) as f64; + (rng.next_u64() >> 11) as f64 / SCALE } } @@ -198,3 +203,19 @@ impl<T: Rand + 'static> Rand for @T { #[inline] fn rand<R: Rng>(rng: &mut R) -> @T { @rng.gen() } } + +#[cfg(test)] +mod tests { + use rand::Rng; + struct ConstantRng(u64); + impl Rng for ConstantRng { + fn next_u64(&mut self) -> u64 { + **self + } + } + fn floating_point_edge_cases() { + // the test for exact equality is correct here. + assert!(ConstantRng(0xffff_ffff).gen::<f32>() != 1.0) + assert!(ConstantRng(0xffff_ffff_ffff_ffff).gen::<f64>() != 1.0) + } +} |
