1 // Copyright 2018 Developers of the Rand project. 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your 6 // option. This file may not be copied, modified, or distributed 7 // except according to those terms. 8 9 //! Basic floating-point number distributions 10 11 use core::mem; 12 use Rng; 13 use distributions::{Distribution, Standard}; 14 use distributions::utils::FloatSIMDUtils; 15 #[cfg(feature="simd_support")] 16 use packed_simd::*; 17 18 /// A distribution to sample floating point numbers uniformly in the half-open 19 /// interval `(0, 1]`, i.e. including 1 but not 0. 20 /// 21 /// All values that can be generated are of the form `n * ε/2`. For `f32` 22 /// the 23 most significant random bits of a `u32` are used and for `f64` the 23 /// 53 most significant bits of a `u64` are used. The conversion uses the 24 /// multiplicative method. 25 /// 26 /// See also: [`Standard`] which samples from `[0, 1)`, [`Open01`] 27 /// which samples from `(0, 1)` and [`Uniform`] which samples from arbitrary 28 /// ranges. 29 /// 30 /// # Example 31 /// ``` 32 /// use rand::{thread_rng, Rng}; 33 /// use rand::distributions::OpenClosed01; 34 /// 35 /// let val: f32 = thread_rng().sample(OpenClosed01); 36 /// println!("f32 from (0, 1): {}", val); 37 /// ``` 38 /// 39 /// [`Standard`]: crate::distributions::Standard 40 /// [`Open01`]: crate::distributions::Open01 41 /// [`Uniform`]: crate::distributions::uniform::Uniform 42 #[derive(Clone, Copy, Debug)] 43 pub struct OpenClosed01; 44 45 /// A distribution to sample floating point numbers uniformly in the open 46 /// interval `(0, 1)`, i.e. not including either endpoint. 47 /// 48 /// All values that can be generated are of the form `n * ε + ε/2`. For `f32` 49 /// the 22 most significant random bits of an `u32` are used, for `f64` 52 from 50 /// an `u64`. The conversion uses a transmute-based method. 51 /// 52 /// See also: [`Standard`] which samples from `[0, 1)`, [`OpenClosed01`] 53 /// which samples from `(0, 1]` and [`Uniform`] which samples from arbitrary 54 /// ranges. 55 /// 56 /// # Example 57 /// ``` 58 /// use rand::{thread_rng, Rng}; 59 /// use rand::distributions::Open01; 60 /// 61 /// let val: f32 = thread_rng().sample(Open01); 62 /// println!("f32 from (0, 1): {}", val); 63 /// ``` 64 /// 65 /// [`Standard`]: crate::distributions::Standard 66 /// [`OpenClosed01`]: crate::distributions::OpenClosed01 67 /// [`Uniform`]: crate::distributions::uniform::Uniform 68 #[derive(Clone, Copy, Debug)] 69 pub struct Open01; 70 71 72 pub(crate) trait IntoFloat { 73 type F; 74 75 /// Helper method to combine the fraction and a contant exponent into a 76 /// float. 77 /// 78 /// Only the least significant bits of `self` may be set, 23 for `f32` and 79 /// 52 for `f64`. 80 /// The resulting value will fall in a range that depends on the exponent. 81 /// As an example the range with exponent 0 will be 82 /// [2<sup>0</sup>..2<sup>1</sup>), which is [1..2). into_float_with_exponent(self, exponent: i32) -> Self::F83 fn into_float_with_exponent(self, exponent: i32) -> Self::F; 84 } 85 86 macro_rules! float_impls { 87 ($ty:ident, $uty:ident, $f_scalar:ident, $u_scalar:ty, 88 $fraction_bits:expr, $exponent_bias:expr) => { 89 impl IntoFloat for $uty { 90 type F = $ty; 91 #[inline(always)] 92 fn into_float_with_exponent(self, exponent: i32) -> $ty { 93 // The exponent is encoded using an offset-binary representation 94 let exponent_bits: $u_scalar = 95 (($exponent_bias + exponent) as $u_scalar) << $fraction_bits; 96 // TODO: use from_bits when min compiler > 1.25 (see #545) 97 // $ty::from_bits(self | exponent_bits) 98 unsafe{ mem::transmute(self | exponent_bits) } 99 } 100 } 101 102 impl Distribution<$ty> for Standard { 103 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { 104 // Multiply-based method; 24/53 random bits; [0, 1) interval. 105 // We use the most significant bits because for simple RNGs 106 // those are usually more random. 107 let float_size = mem::size_of::<$f_scalar>() as u32 * 8; 108 let precision = $fraction_bits + 1; 109 let scale = 1.0 / ((1 as $u_scalar << precision) as $f_scalar); 110 111 let value: $uty = rng.gen(); 112 let value = value >> (float_size - precision); 113 scale * $ty::cast_from_int(value) 114 } 115 } 116 117 impl Distribution<$ty> for OpenClosed01 { 118 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { 119 // Multiply-based method; 24/53 random bits; (0, 1] interval. 120 // We use the most significant bits because for simple RNGs 121 // those are usually more random. 122 let float_size = mem::size_of::<$f_scalar>() as u32 * 8; 123 let precision = $fraction_bits + 1; 124 let scale = 1.0 / ((1 as $u_scalar << precision) as $f_scalar); 125 126 let value: $uty = rng.gen(); 127 let value = value >> (float_size - precision); 128 // Add 1 to shift up; will not overflow because of right-shift: 129 scale * $ty::cast_from_int(value + 1) 130 } 131 } 132 133 impl Distribution<$ty> for Open01 { 134 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { 135 // Transmute-based method; 23/52 random bits; (0, 1) interval. 136 // We use the most significant bits because for simple RNGs 137 // those are usually more random. 138 use core::$f_scalar::EPSILON; 139 let float_size = mem::size_of::<$f_scalar>() as u32 * 8; 140 141 let value: $uty = rng.gen(); 142 let fraction = value >> (float_size - $fraction_bits); 143 fraction.into_float_with_exponent(0) - (1.0 - EPSILON / 2.0) 144 } 145 } 146 } 147 } 148 149 float_impls! { f32, u32, f32, u32, 23, 127 } 150 float_impls! { f64, u64, f64, u64, 52, 1023 } 151 152 #[cfg(feature="simd_support")] 153 float_impls! { f32x2, u32x2, f32, u32, 23, 127 } 154 #[cfg(feature="simd_support")] 155 float_impls! { f32x4, u32x4, f32, u32, 23, 127 } 156 #[cfg(feature="simd_support")] 157 float_impls! { f32x8, u32x8, f32, u32, 23, 127 } 158 #[cfg(feature="simd_support")] 159 float_impls! { f32x16, u32x16, f32, u32, 23, 127 } 160 161 #[cfg(feature="simd_support")] 162 float_impls! { f64x2, u64x2, f64, u64, 52, 1023 } 163 #[cfg(feature="simd_support")] 164 float_impls! { f64x4, u64x4, f64, u64, 52, 1023 } 165 #[cfg(feature="simd_support")] 166 float_impls! { f64x8, u64x8, f64, u64, 52, 1023 } 167 168 169 #[cfg(test)] 170 mod tests { 171 use Rng; 172 use distributions::{Open01, OpenClosed01}; 173 use rngs::mock::StepRng; 174 #[cfg(feature="simd_support")] 175 use packed_simd::*; 176 177 const EPSILON32: f32 = ::core::f32::EPSILON; 178 const EPSILON64: f64 = ::core::f64::EPSILON; 179 180 macro_rules! test_f32 { 181 ($fnn:ident, $ty:ident, $ZERO:expr, $EPSILON:expr) => { 182 #[test] 183 fn $fnn() { 184 // Standard 185 let mut zeros = StepRng::new(0, 0); 186 assert_eq!(zeros.gen::<$ty>(), $ZERO); 187 let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0); 188 assert_eq!(one.gen::<$ty>(), $EPSILON / 2.0); 189 let mut max = StepRng::new(!0, 0); 190 assert_eq!(max.gen::<$ty>(), 1.0 - $EPSILON / 2.0); 191 192 // OpenClosed01 193 let mut zeros = StepRng::new(0, 0); 194 assert_eq!(zeros.sample::<$ty, _>(OpenClosed01), 195 0.0 + $EPSILON / 2.0); 196 let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0); 197 assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON); 198 let mut max = StepRng::new(!0, 0); 199 assert_eq!(max.sample::<$ty, _>(OpenClosed01), $ZERO + 1.0); 200 201 // Open01 202 let mut zeros = StepRng::new(0, 0); 203 assert_eq!(zeros.sample::<$ty, _>(Open01), 0.0 + $EPSILON / 2.0); 204 let mut one = StepRng::new(1 << 9 | 1 << (9 + 32), 0); 205 assert_eq!(one.sample::<$ty, _>(Open01), $EPSILON / 2.0 * 3.0); 206 let mut max = StepRng::new(!0, 0); 207 assert_eq!(max.sample::<$ty, _>(Open01), 1.0 - $EPSILON / 2.0); 208 } 209 } 210 } 211 test_f32! { f32_edge_cases, f32, 0.0, EPSILON32 } 212 #[cfg(feature="simd_support")] 213 test_f32! { f32x2_edge_cases, f32x2, f32x2::splat(0.0), f32x2::splat(EPSILON32) } 214 #[cfg(feature="simd_support")] 215 test_f32! { f32x4_edge_cases, f32x4, f32x4::splat(0.0), f32x4::splat(EPSILON32) } 216 #[cfg(feature="simd_support")] 217 test_f32! { f32x8_edge_cases, f32x8, f32x8::splat(0.0), f32x8::splat(EPSILON32) } 218 #[cfg(feature="simd_support")] 219 test_f32! { f32x16_edge_cases, f32x16, f32x16::splat(0.0), f32x16::splat(EPSILON32) } 220 221 macro_rules! test_f64 { 222 ($fnn:ident, $ty:ident, $ZERO:expr, $EPSILON:expr) => { 223 #[test] 224 fn $fnn() { 225 // Standard 226 let mut zeros = StepRng::new(0, 0); 227 assert_eq!(zeros.gen::<$ty>(), $ZERO); 228 let mut one = StepRng::new(1 << 11, 0); 229 assert_eq!(one.gen::<$ty>(), $EPSILON / 2.0); 230 let mut max = StepRng::new(!0, 0); 231 assert_eq!(max.gen::<$ty>(), 1.0 - $EPSILON / 2.0); 232 233 // OpenClosed01 234 let mut zeros = StepRng::new(0, 0); 235 assert_eq!(zeros.sample::<$ty, _>(OpenClosed01), 236 0.0 + $EPSILON / 2.0); 237 let mut one = StepRng::new(1 << 11, 0); 238 assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON); 239 let mut max = StepRng::new(!0, 0); 240 assert_eq!(max.sample::<$ty, _>(OpenClosed01), $ZERO + 1.0); 241 242 // Open01 243 let mut zeros = StepRng::new(0, 0); 244 assert_eq!(zeros.sample::<$ty, _>(Open01), 0.0 + $EPSILON / 2.0); 245 let mut one = StepRng::new(1 << 12, 0); 246 assert_eq!(one.sample::<$ty, _>(Open01), $EPSILON / 2.0 * 3.0); 247 let mut max = StepRng::new(!0, 0); 248 assert_eq!(max.sample::<$ty, _>(Open01), 1.0 - $EPSILON / 2.0); 249 } 250 } 251 } 252 test_f64! { f64_edge_cases, f64, 0.0, EPSILON64 } 253 #[cfg(feature="simd_support")] 254 test_f64! { f64x2_edge_cases, f64x2, f64x2::splat(0.0), f64x2::splat(EPSILON64) } 255 #[cfg(feature="simd_support")] 256 test_f64! { f64x4_edge_cases, f64x4, f64x4::splat(0.0), f64x4::splat(EPSILON64) } 257 #[cfg(feature="simd_support")] 258 test_f64! { f64x8_edge_cases, f64x8, f64x8::splat(0.0), f64x8::splat(EPSILON64) } 259 } 260