1 // Copyright 2018 Developers of the Rand project.
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.
9 //! Basic floating-point number distributions
13 use crate::distributions
::{Distribution, Standard}
;
14 use crate::distributions
::utils
::FloatSIMDUtils
;
15 #[cfg(feature="simd_support")]
18 /// A distribution to sample floating point numbers uniformly in the half-open
19 /// interval `(0, 1]`, i.e. including 1 but not 0.
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.
26 /// See also: [`Standard`] which samples from `[0, 1)`, [`Open01`]
27 /// which samples from `(0, 1)` and [`Uniform`] which samples from arbitrary
32 /// use rand::{thread_rng, Rng};
33 /// use rand::distributions::OpenClosed01;
35 /// let val: f32 = thread_rng().sample(OpenClosed01);
36 /// println!("f32 from (0, 1): {}", val);
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
;
45 /// A distribution to sample floating point numbers uniformly in the open
46 /// interval `(0, 1)`, i.e. not including either endpoint.
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.
52 /// See also: [`Standard`] which samples from `[0, 1)`, [`OpenClosed01`]
53 /// which samples from `(0, 1]` and [`Uniform`] which samples from arbitrary
58 /// use rand::{thread_rng, Rng};
59 /// use rand::distributions::Open01;
61 /// let val: f32 = thread_rng().sample(Open01);
62 /// println!("f32 from (0, 1): {}", val);
65 /// [`Standard`]: crate::distributions::Standard
66 /// [`OpenClosed01`]: crate::distributions::OpenClosed01
67 /// [`Uniform`]: crate::distributions::uniform::Uniform
68 #[derive(Clone, Copy, Debug)]
72 // This trait is needed by both this lib and rand_distr hence is a hidden export
77 /// Helper method to combine the fraction and a contant exponent into a
80 /// Only the least significant bits of `self` may be set, 23 for `f32` and
82 /// The resulting value will fall in a range that depends on the exponent.
83 /// As an example the range with exponent 0 will be
84 /// [2<sup>0</sup>..2<sup>1</sup>), which is [1..2).
85 fn into_float_with_exponent(self, exponent
: i32) -> Self::F
;
88 macro_rules
! float_impls
{
89 ($ty
:ident
, $uty
:ident
, $f_scalar
:ident
, $u_scalar
:ty
,
90 $fraction_bits
:expr
, $exponent_bias
:expr
) => {
91 impl IntoFloat
for $uty
{
94 fn into_float_with_exponent(self, exponent
: i32) -> $ty
{
95 // The exponent is encoded using an offset-binary representation
96 let exponent_bits
: $u_scalar
=
97 (($exponent_bias
+ exponent
) as $u_scalar
) << $fraction_bits
;
98 // TODO: use from_bits when min compiler > 1.25 (see #545)
99 // $ty::from_bits(self | exponent_bits)
100 unsafe{ mem::transmute(self | exponent_bits) }
104 impl Distribution
<$ty
> for Standard
{
105 fn sample
<R
: Rng
+ ?Sized
>(&self, rng
: &mut R
) -> $ty
{
106 // Multiply-based method; 24/53 random bits; [0, 1) interval.
107 // We use the most significant bits because for simple RNGs
108 // those are usually more random.
109 let float_size
= mem
::size_of
::<$f_scalar
>() as u32 * 8;
110 let precision
= $fraction_bits
+ 1;
111 let scale
= 1.0 / ((1 as $u_scalar
<< precision
) as $f_scalar
);
113 let value
: $uty
= rng
.gen();
114 let value
= value
>> (float_size
- precision
);
115 scale
* $ty
::cast_from_int(value
)
119 impl Distribution
<$ty
> for OpenClosed01
{
120 fn sample
<R
: Rng
+ ?Sized
>(&self, rng
: &mut R
) -> $ty
{
121 // Multiply-based method; 24/53 random bits; (0, 1] interval.
122 // We use the most significant bits because for simple RNGs
123 // those are usually more random.
124 let float_size
= mem
::size_of
::<$f_scalar
>() as u32 * 8;
125 let precision
= $fraction_bits
+ 1;
126 let scale
= 1.0 / ((1 as $u_scalar
<< precision
) as $f_scalar
);
128 let value
: $uty
= rng
.gen();
129 let value
= value
>> (float_size
- precision
);
130 // Add 1 to shift up; will not overflow because of right-shift:
131 scale
* $ty
::cast_from_int(value
+ 1)
135 impl Distribution
<$ty
> for Open01
{
136 fn sample
<R
: Rng
+ ?Sized
>(&self, rng
: &mut R
) -> $ty
{
137 // Transmute-based method; 23/52 random bits; (0, 1) interval.
138 // We use the most significant bits because for simple RNGs
139 // those are usually more random.
140 use core
::$f_scalar
::EPSILON
;
141 let float_size
= mem
::size_of
::<$f_scalar
>() as u32 * 8;
143 let value
: $uty
= rng
.gen();
144 let fraction
= value
>> (float_size
- $fraction_bits
);
145 fraction
.into_float_with_exponent(0) - (1.0 - EPSILON
/ 2.0)
151 float_impls
! { f32, u32, f32, u32, 23, 127 }
152 float_impls
! { f64, u64, f64, u64, 52, 1023 }
154 #[cfg(feature="simd_support")]
155 float_impls
! { f32x2, u32x2, f32, u32, 23, 127 }
156 #[cfg(feature="simd_support")]
157 float_impls
! { f32x4, u32x4, f32, u32, 23, 127 }
158 #[cfg(feature="simd_support")]
159 float_impls
! { f32x8, u32x8, f32, u32, 23, 127 }
160 #[cfg(feature="simd_support")]
161 float_impls
! { f32x16, u32x16, f32, u32, 23, 127 }
163 #[cfg(feature="simd_support")]
164 float_impls
! { f64x2, u64x2, f64, u64, 52, 1023 }
165 #[cfg(feature="simd_support")]
166 float_impls
! { f64x4, u64x4, f64, u64, 52, 1023 }
167 #[cfg(feature="simd_support")]
168 float_impls
! { f64x8, u64x8, f64, u64, 52, 1023 }
174 use crate::distributions
::{Open01, OpenClosed01}
;
175 use crate::rngs
::mock
::StepRng
;
176 #[cfg(feature="simd_support")]
179 const EPSILON32
: f32 = ::core
::f32::EPSILON
;
180 const EPSILON64
: f64 = ::core
::f64::EPSILON
;
182 macro_rules
! test_f32
{
183 ($fnn
:ident
, $ty
:ident
, $ZERO
:expr
, $EPSILON
:expr
) => {
187 let mut zeros
= StepRng
::new(0, 0);
188 assert_eq
!(zeros
.gen
::<$ty
>(), $ZERO
);
189 let mut one
= StepRng
::new(1 << 8 | 1 << (8 + 32), 0);
190 assert_eq
!(one
.gen
::<$ty
>(), $EPSILON
/ 2.0);
191 let mut max
= StepRng
::new(!0, 0);
192 assert_eq
!(max
.gen
::<$ty
>(), 1.0 - $EPSILON
/ 2.0);
195 let mut zeros
= StepRng
::new(0, 0);
196 assert_eq
!(zeros
.sample
::<$ty
, _
>(OpenClosed01
),
197 0.0 + $EPSILON
/ 2.0);
198 let mut one
= StepRng
::new(1 << 8 | 1 << (8 + 32), 0);
199 assert_eq
!(one
.sample
::<$ty
, _
>(OpenClosed01
), $EPSILON
);
200 let mut max
= StepRng
::new(!0, 0);
201 assert_eq
!(max
.sample
::<$ty
, _
>(OpenClosed01
), $ZERO
+ 1.0);
204 let mut zeros
= StepRng
::new(0, 0);
205 assert_eq
!(zeros
.sample
::<$ty
, _
>(Open01
), 0.0 + $EPSILON
/ 2.0);
206 let mut one
= StepRng
::new(1 << 9 | 1 << (9 + 32), 0);
207 assert_eq
!(one
.sample
::<$ty
, _
>(Open01
), $EPSILON
/ 2.0 * 3.0);
208 let mut max
= StepRng
::new(!0, 0);
209 assert_eq
!(max
.sample
::<$ty
, _
>(Open01
), 1.0 - $EPSILON
/ 2.0);
213 test_f32
! { f32_edge_cases, f32, 0.0, EPSILON32 }
214 #[cfg(feature="simd_support")]
215 test_f32
! { f32x2_edge_cases, f32x2, f32x2::splat(0.0), f32x2::splat(EPSILON32) }
216 #[cfg(feature="simd_support")]
217 test_f32
! { f32x4_edge_cases, f32x4, f32x4::splat(0.0), f32x4::splat(EPSILON32) }
218 #[cfg(feature="simd_support")]
219 test_f32
! { f32x8_edge_cases, f32x8, f32x8::splat(0.0), f32x8::splat(EPSILON32) }
220 #[cfg(feature="simd_support")]
221 test_f32
! { f32x16_edge_cases, f32x16, f32x16::splat(0.0), f32x16::splat(EPSILON32) }
223 macro_rules
! test_f64
{
224 ($fnn
:ident
, $ty
:ident
, $ZERO
:expr
, $EPSILON
:expr
) => {
228 let mut zeros
= StepRng
::new(0, 0);
229 assert_eq
!(zeros
.gen
::<$ty
>(), $ZERO
);
230 let mut one
= StepRng
::new(1 << 11, 0);
231 assert_eq
!(one
.gen
::<$ty
>(), $EPSILON
/ 2.0);
232 let mut max
= StepRng
::new(!0, 0);
233 assert_eq
!(max
.gen
::<$ty
>(), 1.0 - $EPSILON
/ 2.0);
236 let mut zeros
= StepRng
::new(0, 0);
237 assert_eq
!(zeros
.sample
::<$ty
, _
>(OpenClosed01
),
238 0.0 + $EPSILON
/ 2.0);
239 let mut one
= StepRng
::new(1 << 11, 0);
240 assert_eq
!(one
.sample
::<$ty
, _
>(OpenClosed01
), $EPSILON
);
241 let mut max
= StepRng
::new(!0, 0);
242 assert_eq
!(max
.sample
::<$ty
, _
>(OpenClosed01
), $ZERO
+ 1.0);
245 let mut zeros
= StepRng
::new(0, 0);
246 assert_eq
!(zeros
.sample
::<$ty
, _
>(Open01
), 0.0 + $EPSILON
/ 2.0);
247 let mut one
= StepRng
::new(1 << 12, 0);
248 assert_eq
!(one
.sample
::<$ty
, _
>(Open01
), $EPSILON
/ 2.0 * 3.0);
249 let mut max
= StepRng
::new(!0, 0);
250 assert_eq
!(max
.sample
::<$ty
, _
>(Open01
), 1.0 - $EPSILON
/ 2.0);
254 test_f64
! { f64_edge_cases, f64, 0.0, EPSILON64 }
255 #[cfg(feature="simd_support")]
256 test_f64
! { f64x2_edge_cases, f64x2, f64x2::splat(0.0), f64x2::splat(EPSILON64) }
257 #[cfg(feature="simd_support")]
258 test_f64
! { f64x4_edge_cases, f64x4, f64x4::splat(0.0), f64x4::splat(EPSILON64) }
259 #[cfg(feature="simd_support")]
260 test_f64
! { f64x8_edge_cases, f64x8, f64x8::splat(0.0), f64x8::splat(EPSILON64) }