1 | // Copyright 2018-2020 Developers of the Rand project. |
2 | // Copyright 2017 The Rust Project Developers. |
3 | // |
4 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
5 | // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
6 | // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
7 | // option. This file may not be copied, modified, or distributed |
8 | // except according to those terms. |
9 | |
10 | //! A distribution uniformly sampling numbers within a given range. |
11 | //! |
12 | //! [`Uniform`] is the standard distribution to sample uniformly from a range; |
13 | //! e.g. `Uniform::new_inclusive(1, 6).unwrap()` can sample integers from 1 to 6, like a |
14 | //! standard die. [`Rng::random_range`] is implemented over [`Uniform`]. |
15 | //! |
16 | //! # Example usage |
17 | //! |
18 | //! ``` |
19 | //! use rand::Rng; |
20 | //! use rand::distr::Uniform; |
21 | //! |
22 | //! let mut rng = rand::rng(); |
23 | //! let side = Uniform::new(-10.0, 10.0).unwrap(); |
24 | //! |
25 | //! // sample between 1 and 10 points |
26 | //! for _ in 0..rng.random_range(1..=10) { |
27 | //! // sample a point from the square with sides -10 - 10 in two dimensions |
28 | //! let (x, y) = (rng.sample(side), rng.sample(side)); |
29 | //! println!("Point: {}, {}" , x, y); |
30 | //! } |
31 | //! ``` |
32 | //! |
33 | //! # Extending `Uniform` to support a custom type |
34 | //! |
35 | //! To extend [`Uniform`] to support your own types, write a back-end which |
36 | //! implements the [`UniformSampler`] trait, then implement the [`SampleUniform`] |
37 | //! helper trait to "register" your back-end. See the `MyF32` example below. |
38 | //! |
39 | //! At a minimum, the back-end needs to store any parameters needed for sampling |
40 | //! (e.g. the target range) and implement `new`, `new_inclusive` and `sample`. |
41 | //! Those methods should include an assertion to check the range is valid (i.e. |
42 | //! `low < high`). The example below merely wraps another back-end. |
43 | //! |
44 | //! The `new`, `new_inclusive`, `sample_single` and `sample_single_inclusive` |
45 | //! functions use arguments of |
46 | //! type `SampleBorrow<X>` to support passing in values by reference or |
47 | //! by value. In the implementation of these functions, you can choose to |
48 | //! simply use the reference returned by [`SampleBorrow::borrow`], or you can choose |
49 | //! to copy or clone the value, whatever is appropriate for your type. |
50 | //! |
51 | //! ``` |
52 | //! use rand::prelude::*; |
53 | //! use rand::distr::uniform::{Uniform, SampleUniform, |
54 | //! UniformSampler, UniformFloat, SampleBorrow, Error}; |
55 | //! |
56 | //! struct MyF32(f32); |
57 | //! |
58 | //! #[derive(Clone, Copy, Debug)] |
59 | //! struct UniformMyF32(UniformFloat<f32>); |
60 | //! |
61 | //! impl UniformSampler for UniformMyF32 { |
62 | //! type X = MyF32; |
63 | //! |
64 | //! fn new<B1, B2>(low: B1, high: B2) -> Result<Self, Error> |
65 | //! where B1: SampleBorrow<Self::X> + Sized, |
66 | //! B2: SampleBorrow<Self::X> + Sized |
67 | //! { |
68 | //! UniformFloat::<f32>::new(low.borrow().0, high.borrow().0).map(UniformMyF32) |
69 | //! } |
70 | //! fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Self, Error> |
71 | //! where B1: SampleBorrow<Self::X> + Sized, |
72 | //! B2: SampleBorrow<Self::X> + Sized |
73 | //! { |
74 | //! UniformFloat::<f32>::new_inclusive(low.borrow().0, high.borrow().0).map(UniformMyF32) |
75 | //! } |
76 | //! fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { |
77 | //! MyF32(self.0.sample(rng)) |
78 | //! } |
79 | //! } |
80 | //! |
81 | //! impl SampleUniform for MyF32 { |
82 | //! type Sampler = UniformMyF32; |
83 | //! } |
84 | //! |
85 | //! let (low, high) = (MyF32(17.0f32), MyF32(22.0f32)); |
86 | //! let uniform = Uniform::new(low, high).unwrap(); |
87 | //! let x = uniform.sample(&mut rand::rng()); |
88 | //! ``` |
89 | //! |
90 | //! [`SampleUniform`]: crate::distr::uniform::SampleUniform |
91 | //! [`UniformSampler`]: crate::distr::uniform::UniformSampler |
92 | //! [`UniformInt`]: crate::distr::uniform::UniformInt |
93 | //! [`UniformFloat`]: crate::distr::uniform::UniformFloat |
94 | //! [`UniformDuration`]: crate::distr::uniform::UniformDuration |
95 | //! [`SampleBorrow::borrow`]: crate::distr::uniform::SampleBorrow::borrow |
96 | |
97 | #[path = "uniform_float.rs" ] |
98 | mod float; |
99 | #[doc (inline)] |
100 | pub use float::UniformFloat; |
101 | |
102 | #[path = "uniform_int.rs" ] |
103 | mod int; |
104 | #[doc (inline)] |
105 | pub use int::{UniformInt, UniformUsize}; |
106 | |
107 | #[path = "uniform_other.rs" ] |
108 | mod other; |
109 | #[doc (inline)] |
110 | pub use other::{UniformChar, UniformDuration}; |
111 | |
112 | use core::fmt; |
113 | use core::ops::{Range, RangeInclusive, RangeTo, RangeToInclusive}; |
114 | |
115 | use crate::distr::Distribution; |
116 | use crate::{Rng, RngCore}; |
117 | |
118 | /// Error type returned from [`Uniform::new`] and `new_inclusive`. |
119 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
120 | pub enum Error { |
121 | /// `low > high`, or equal in case of exclusive range. |
122 | EmptyRange, |
123 | /// Input or range `high - low` is non-finite. Not relevant to integer types. |
124 | NonFinite, |
125 | } |
126 | |
127 | impl fmt::Display for Error { |
128 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
129 | f.write_str(match self { |
130 | Error::EmptyRange => "low > high (or equal if exclusive) in uniform distribution" , |
131 | Error::NonFinite => "Non-finite range in uniform distribution" , |
132 | }) |
133 | } |
134 | } |
135 | |
136 | #[cfg (feature = "std" )] |
137 | impl std::error::Error for Error {} |
138 | |
139 | #[cfg (feature = "serde" )] |
140 | use serde::{Deserialize, Serialize}; |
141 | |
142 | /// Sample values uniformly between two bounds. |
143 | /// |
144 | /// # Construction |
145 | /// |
146 | /// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a uniform |
147 | /// distribution sampling from the given `low` and `high` limits. `Uniform` may |
148 | /// also be constructed via [`TryFrom`] as in `Uniform::try_from(1..=6).unwrap()`. |
149 | /// |
150 | /// Constructors may do extra work up front to allow faster sampling of multiple |
151 | /// values. Where only a single sample is required it is suggested to use |
152 | /// [`Rng::random_range`] or one of the `sample_single` methods instead. |
153 | /// |
154 | /// When sampling from a constant range, many calculations can happen at |
155 | /// compile-time and all methods should be fast; for floating-point ranges and |
156 | /// the full range of integer types, this should have comparable performance to |
157 | /// the [`StandardUniform`](super::StandardUniform) distribution. |
158 | /// |
159 | /// # Provided implementations |
160 | /// |
161 | /// - `char` ([`UniformChar`]): samples a range over the implementation for `u32` |
162 | /// - `f32`, `f64` ([`UniformFloat`]): samples approximately uniformly within a |
163 | /// range; bias may be present in the least-significant bit of the significand |
164 | /// and the limits of the input range may be sampled even when an open |
165 | /// (exclusive) range is used |
166 | /// - Integer types ([`UniformInt`]) may show a small bias relative to the |
167 | /// expected uniform distribution of output. In the worst case, bias affects |
168 | /// 1 in `2^n` samples where n is 56 (`i8` and `u8`), 48 (`i16` and `u16`), 96 |
169 | /// (`i32` and `u32`), 64 (`i64` and `u64`), 128 (`i128` and `u128`). |
170 | /// The `unbiased` feature flag fixes this bias. |
171 | /// - `usize` ([`UniformUsize`]) is handled specially, using the `u32` |
172 | /// implementation where possible to enable portable results across 32-bit and |
173 | /// 64-bit CPU architectures. |
174 | /// - `Duration` ([`UniformDuration`]): samples a range over the implementation |
175 | /// for `u32` or `u64` |
176 | /// - SIMD types (requires [`simd_support`] feature) like x86's [`__m128i`] |
177 | /// and `std::simd`'s [`u32x4`], [`f32x4`] and [`mask32x4`] types are |
178 | /// effectively arrays of integer or floating-point types. Each lane is |
179 | /// sampled independently from its own range, potentially with more efficient |
180 | /// random-bit-usage than would be achieved with sequential sampling. |
181 | /// |
182 | /// # Example |
183 | /// |
184 | /// ``` |
185 | /// use rand::distr::{Distribution, Uniform}; |
186 | /// |
187 | /// let between = Uniform::try_from(10..10000).unwrap(); |
188 | /// let mut rng = rand::rng(); |
189 | /// let mut sum = 0; |
190 | /// for _ in 0..1000 { |
191 | /// sum += between.sample(&mut rng); |
192 | /// } |
193 | /// println!("{}" , sum); |
194 | /// ``` |
195 | /// |
196 | /// For a single sample, [`Rng::random_range`] may be preferred: |
197 | /// |
198 | /// ``` |
199 | /// use rand::Rng; |
200 | /// |
201 | /// let mut rng = rand::rng(); |
202 | /// println!("{}" , rng.random_range(0..10)); |
203 | /// ``` |
204 | /// |
205 | /// [`new`]: Uniform::new |
206 | /// [`new_inclusive`]: Uniform::new_inclusive |
207 | /// [`Rng::random_range`]: Rng::random_range |
208 | /// [`__m128i`]: https://doc.rust-lang.org/core/arch/x86/struct.__m128i.html |
209 | /// [`u32x4`]: std::simd::u32x4 |
210 | /// [`f32x4`]: std::simd::f32x4 |
211 | /// [`mask32x4`]: std::simd::mask32x4 |
212 | /// [`simd_support`]: https://github.com/rust-random/rand#crate-features |
213 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
214 | #[cfg_attr (feature = "serde" , derive(Serialize, Deserialize))] |
215 | #[cfg_attr (feature = "serde" , serde(bound(serialize = "X::Sampler: Serialize" )))] |
216 | #[cfg_attr ( |
217 | feature = "serde" , |
218 | serde(bound(deserialize = "X::Sampler: Deserialize<'de>" )) |
219 | )] |
220 | pub struct Uniform<X: SampleUniform>(X::Sampler); |
221 | |
222 | impl<X: SampleUniform> Uniform<X> { |
223 | /// Create a new `Uniform` instance, which samples uniformly from the half |
224 | /// open range `[low, high)` (excluding `high`). |
225 | /// |
226 | /// For discrete types (e.g. integers), samples will always be strictly less |
227 | /// than `high`. For (approximations of) continuous types (e.g. `f32`, `f64`), |
228 | /// samples may equal `high` due to loss of precision but may not be |
229 | /// greater than `high`. |
230 | /// |
231 | /// Fails if `low >= high`, or if `low`, `high` or the range `high - low` is |
232 | /// non-finite. In release mode, only the range is checked. |
233 | pub fn new<B1, B2>(low: B1, high: B2) -> Result<Uniform<X>, Error> |
234 | where |
235 | B1: SampleBorrow<X> + Sized, |
236 | B2: SampleBorrow<X> + Sized, |
237 | { |
238 | X::Sampler::new(low, high).map(Uniform) |
239 | } |
240 | |
241 | /// Create a new `Uniform` instance, which samples uniformly from the closed |
242 | /// range `[low, high]` (inclusive). |
243 | /// |
244 | /// Fails if `low > high`, or if `low`, `high` or the range `high - low` is |
245 | /// non-finite. In release mode, only the range is checked. |
246 | pub fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Uniform<X>, Error> |
247 | where |
248 | B1: SampleBorrow<X> + Sized, |
249 | B2: SampleBorrow<X> + Sized, |
250 | { |
251 | X::Sampler::new_inclusive(low, high).map(Uniform) |
252 | } |
253 | } |
254 | |
255 | impl<X: SampleUniform> Distribution<X> for Uniform<X> { |
256 | fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> X { |
257 | self.0.sample(rng) |
258 | } |
259 | } |
260 | |
261 | /// Helper trait for creating objects using the correct implementation of |
262 | /// [`UniformSampler`] for the sampling type. |
263 | /// |
264 | /// See the [module documentation] on how to implement [`Uniform`] range |
265 | /// sampling for a custom type. |
266 | /// |
267 | /// [module documentation]: crate::distr::uniform |
268 | pub trait SampleUniform: Sized { |
269 | /// The `UniformSampler` implementation supporting type `X`. |
270 | type Sampler: UniformSampler<X = Self>; |
271 | } |
272 | |
273 | /// Helper trait handling actual uniform sampling. |
274 | /// |
275 | /// See the [module documentation] on how to implement [`Uniform`] range |
276 | /// sampling for a custom type. |
277 | /// |
278 | /// Implementation of [`sample_single`] is optional, and is only useful when |
279 | /// the implementation can be faster than `Self::new(low, high).sample(rng)`. |
280 | /// |
281 | /// [module documentation]: crate::distr::uniform |
282 | /// [`sample_single`]: UniformSampler::sample_single |
283 | pub trait UniformSampler: Sized { |
284 | /// The type sampled by this implementation. |
285 | type X; |
286 | |
287 | /// Construct self, with inclusive lower bound and exclusive upper bound `[low, high)`. |
288 | /// |
289 | /// For discrete types (e.g. integers), samples will always be strictly less |
290 | /// than `high`. For (approximations of) continuous types (e.g. `f32`, `f64`), |
291 | /// samples may equal `high` due to loss of precision but may not be |
292 | /// greater than `high`. |
293 | /// |
294 | /// Usually users should not call this directly but prefer to use |
295 | /// [`Uniform::new`]. |
296 | fn new<B1, B2>(low: B1, high: B2) -> Result<Self, Error> |
297 | where |
298 | B1: SampleBorrow<Self::X> + Sized, |
299 | B2: SampleBorrow<Self::X> + Sized; |
300 | |
301 | /// Construct self, with inclusive bounds `[low, high]`. |
302 | /// |
303 | /// Usually users should not call this directly but prefer to use |
304 | /// [`Uniform::new_inclusive`]. |
305 | fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Self, Error> |
306 | where |
307 | B1: SampleBorrow<Self::X> + Sized, |
308 | B2: SampleBorrow<Self::X> + Sized; |
309 | |
310 | /// Sample a value. |
311 | fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X; |
312 | |
313 | /// Sample a single value uniformly from a range with inclusive lower bound |
314 | /// and exclusive upper bound `[low, high)`. |
315 | /// |
316 | /// For discrete types (e.g. integers), samples will always be strictly less |
317 | /// than `high`. For (approximations of) continuous types (e.g. `f32`, `f64`), |
318 | /// samples may equal `high` due to loss of precision but may not be |
319 | /// greater than `high`. |
320 | /// |
321 | /// By default this is implemented using |
322 | /// `UniformSampler::new(low, high).sample(rng)`. However, for some types |
323 | /// more optimal implementations for single usage may be provided via this |
324 | /// method (which is the case for integers and floats). |
325 | /// Results may not be identical. |
326 | /// |
327 | /// Note that to use this method in a generic context, the type needs to be |
328 | /// retrieved via `SampleUniform::Sampler` as follows: |
329 | /// ``` |
330 | /// use rand::distr::uniform::{SampleUniform, UniformSampler}; |
331 | /// # #[allow (unused)] |
332 | /// fn sample_from_range<T: SampleUniform>(lb: T, ub: T) -> T { |
333 | /// let mut rng = rand::rng(); |
334 | /// <T as SampleUniform>::Sampler::sample_single(lb, ub, &mut rng).unwrap() |
335 | /// } |
336 | /// ``` |
337 | fn sample_single<R: Rng + ?Sized, B1, B2>( |
338 | low: B1, |
339 | high: B2, |
340 | rng: &mut R, |
341 | ) -> Result<Self::X, Error> |
342 | where |
343 | B1: SampleBorrow<Self::X> + Sized, |
344 | B2: SampleBorrow<Self::X> + Sized, |
345 | { |
346 | let uniform: Self = UniformSampler::new(low, high)?; |
347 | Ok(uniform.sample(rng)) |
348 | } |
349 | |
350 | /// Sample a single value uniformly from a range with inclusive lower bound |
351 | /// and inclusive upper bound `[low, high]`. |
352 | /// |
353 | /// By default this is implemented using |
354 | /// `UniformSampler::new_inclusive(low, high).sample(rng)`. However, for |
355 | /// some types more optimal implementations for single usage may be provided |
356 | /// via this method. |
357 | /// Results may not be identical. |
358 | fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>( |
359 | low: B1, |
360 | high: B2, |
361 | rng: &mut R, |
362 | ) -> Result<Self::X, Error> |
363 | where |
364 | B1: SampleBorrow<Self::X> + Sized, |
365 | B2: SampleBorrow<Self::X> + Sized, |
366 | { |
367 | let uniform: Self = UniformSampler::new_inclusive(low, high)?; |
368 | Ok(uniform.sample(rng)) |
369 | } |
370 | } |
371 | |
372 | impl<X: SampleUniform> TryFrom<Range<X>> for Uniform<X> { |
373 | type Error = Error; |
374 | |
375 | fn try_from(r: Range<X>) -> Result<Uniform<X>, Error> { |
376 | Uniform::new(low:r.start, high:r.end) |
377 | } |
378 | } |
379 | |
380 | impl<X: SampleUniform> TryFrom<RangeInclusive<X>> for Uniform<X> { |
381 | type Error = Error; |
382 | |
383 | fn try_from(r: ::core::ops::RangeInclusive<X>) -> Result<Uniform<X>, Error> { |
384 | Uniform::new_inclusive(low:r.start(), high:r.end()) |
385 | } |
386 | } |
387 | |
388 | /// Helper trait similar to [`Borrow`] but implemented |
389 | /// only for [`SampleUniform`] and references to [`SampleUniform`] |
390 | /// in order to resolve ambiguity issues. |
391 | /// |
392 | /// [`Borrow`]: std::borrow::Borrow |
393 | pub trait SampleBorrow<Borrowed> { |
394 | /// Immutably borrows from an owned value. See [`Borrow::borrow`] |
395 | /// |
396 | /// [`Borrow::borrow`]: std::borrow::Borrow::borrow |
397 | fn borrow(&self) -> &Borrowed; |
398 | } |
399 | impl<Borrowed> SampleBorrow<Borrowed> for Borrowed |
400 | where |
401 | Borrowed: SampleUniform, |
402 | { |
403 | #[inline (always)] |
404 | fn borrow(&self) -> &Borrowed { |
405 | self |
406 | } |
407 | } |
408 | impl<Borrowed> SampleBorrow<Borrowed> for &Borrowed |
409 | where |
410 | Borrowed: SampleUniform, |
411 | { |
412 | #[inline (always)] |
413 | fn borrow(&self) -> &Borrowed { |
414 | self |
415 | } |
416 | } |
417 | |
418 | /// Range that supports generating a single sample efficiently. |
419 | /// |
420 | /// Any type implementing this trait can be used to specify the sampled range |
421 | /// for `Rng::random_range`. |
422 | pub trait SampleRange<T> { |
423 | /// Generate a sample from the given range. |
424 | fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> Result<T, Error>; |
425 | |
426 | /// Check whether the range is empty. |
427 | fn is_empty(&self) -> bool; |
428 | } |
429 | |
430 | impl<T: SampleUniform + PartialOrd> SampleRange<T> for Range<T> { |
431 | #[inline ] |
432 | fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> Result<T, Error> { |
433 | T::Sampler::sample_single(self.start, self.end, rng) |
434 | } |
435 | |
436 | #[inline ] |
437 | fn is_empty(&self) -> bool { |
438 | !(self.start < self.end) |
439 | } |
440 | } |
441 | |
442 | impl<T: SampleUniform + PartialOrd> SampleRange<T> for RangeInclusive<T> { |
443 | #[inline ] |
444 | fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> Result<T, Error> { |
445 | T::Sampler::sample_single_inclusive(self.start(), self.end(), rng) |
446 | } |
447 | |
448 | #[inline ] |
449 | fn is_empty(&self) -> bool { |
450 | !(self.start() <= self.end()) |
451 | } |
452 | } |
453 | |
454 | macro_rules! impl_sample_range_u { |
455 | ($t:ty) => { |
456 | impl SampleRange<$t> for RangeTo<$t> { |
457 | #[inline] |
458 | fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> Result<$t, Error> { |
459 | <$t as SampleUniform>::Sampler::sample_single(0, self.end, rng) |
460 | } |
461 | |
462 | #[inline] |
463 | fn is_empty(&self) -> bool { |
464 | 0 == self.end |
465 | } |
466 | } |
467 | |
468 | impl SampleRange<$t> for RangeToInclusive<$t> { |
469 | #[inline] |
470 | fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> Result<$t, Error> { |
471 | <$t as SampleUniform>::Sampler::sample_single_inclusive(0, self.end, rng) |
472 | } |
473 | |
474 | #[inline] |
475 | fn is_empty(&self) -> bool { |
476 | false |
477 | } |
478 | } |
479 | }; |
480 | } |
481 | |
482 | impl_sample_range_u!(u8); |
483 | impl_sample_range_u!(u16); |
484 | impl_sample_range_u!(u32); |
485 | impl_sample_range_u!(u64); |
486 | impl_sample_range_u!(u128); |
487 | impl_sample_range_u!(usize); |
488 | |
489 | #[cfg (test)] |
490 | mod tests { |
491 | use super::*; |
492 | use core::time::Duration; |
493 | |
494 | #[test] |
495 | #[cfg (feature = "serde" )] |
496 | fn test_uniform_serialization() { |
497 | let unit_box: Uniform<i32> = Uniform::new(-1, 1).unwrap(); |
498 | let de_unit_box: Uniform<i32> = |
499 | bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap(); |
500 | assert_eq!(unit_box.0, de_unit_box.0); |
501 | |
502 | let unit_box: Uniform<f32> = Uniform::new(-1., 1.).unwrap(); |
503 | let de_unit_box: Uniform<f32> = |
504 | bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap(); |
505 | assert_eq!(unit_box.0, de_unit_box.0); |
506 | } |
507 | |
508 | #[test] |
509 | fn test_custom_uniform() { |
510 | use crate::distr::uniform::{SampleBorrow, SampleUniform, UniformFloat, UniformSampler}; |
511 | #[derive(Clone, Copy, PartialEq, PartialOrd)] |
512 | struct MyF32 { |
513 | x: f32, |
514 | } |
515 | #[derive(Clone, Copy, Debug)] |
516 | struct UniformMyF32(UniformFloat<f32>); |
517 | impl UniformSampler for UniformMyF32 { |
518 | type X = MyF32; |
519 | |
520 | fn new<B1, B2>(low: B1, high: B2) -> Result<Self, Error> |
521 | where |
522 | B1: SampleBorrow<Self::X> + Sized, |
523 | B2: SampleBorrow<Self::X> + Sized, |
524 | { |
525 | UniformFloat::<f32>::new(low.borrow().x, high.borrow().x).map(UniformMyF32) |
526 | } |
527 | |
528 | fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Self, Error> |
529 | where |
530 | B1: SampleBorrow<Self::X> + Sized, |
531 | B2: SampleBorrow<Self::X> + Sized, |
532 | { |
533 | UniformSampler::new(low, high) |
534 | } |
535 | |
536 | fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { |
537 | MyF32 { |
538 | x: self.0.sample(rng), |
539 | } |
540 | } |
541 | } |
542 | impl SampleUniform for MyF32 { |
543 | type Sampler = UniformMyF32; |
544 | } |
545 | |
546 | let (low, high) = (MyF32 { x: 17.0f32 }, MyF32 { x: 22.0f32 }); |
547 | let uniform = Uniform::new(low, high).unwrap(); |
548 | let mut rng = crate::test::rng(804); |
549 | for _ in 0..100 { |
550 | let x: MyF32 = rng.sample(uniform); |
551 | assert!(low <= x && x < high); |
552 | } |
553 | } |
554 | |
555 | #[test] |
556 | fn value_stability() { |
557 | fn test_samples<T: SampleUniform + Copy + fmt::Debug + PartialEq>( |
558 | lb: T, |
559 | ub: T, |
560 | expected_single: &[T], |
561 | expected_multiple: &[T], |
562 | ) where |
563 | Uniform<T>: Distribution<T>, |
564 | { |
565 | let mut rng = crate::test::rng(897); |
566 | let mut buf = [lb; 3]; |
567 | |
568 | for x in &mut buf { |
569 | *x = T::Sampler::sample_single(lb, ub, &mut rng).unwrap(); |
570 | } |
571 | assert_eq!(&buf, expected_single); |
572 | |
573 | let distr = Uniform::new(lb, ub).unwrap(); |
574 | for x in &mut buf { |
575 | *x = rng.sample(&distr); |
576 | } |
577 | assert_eq!(&buf, expected_multiple); |
578 | } |
579 | |
580 | test_samples( |
581 | 0f32, |
582 | 1e-2f32, |
583 | &[0.0003070104, 0.0026630748, 0.00979833], |
584 | &[0.008194133, 0.00398172, 0.007428536], |
585 | ); |
586 | test_samples( |
587 | -1e10f64, |
588 | 1e10f64, |
589 | &[-4673848682.871551, 6388267422.932352, 4857075081.198343], |
590 | &[1173375212.1808167, 1917642852.109581, 2365076174.3153973], |
591 | ); |
592 | |
593 | test_samples( |
594 | Duration::new(2, 0), |
595 | Duration::new(4, 0), |
596 | &[ |
597 | Duration::new(2, 532615131), |
598 | Duration::new(3, 638826742), |
599 | Duration::new(3, 485707508), |
600 | ], |
601 | &[ |
602 | Duration::new(3, 117337521), |
603 | Duration::new(3, 191764285), |
604 | Duration::new(3, 236507617), |
605 | ], |
606 | ); |
607 | } |
608 | |
609 | #[test] |
610 | fn uniform_distributions_can_be_compared() { |
611 | assert_eq!( |
612 | Uniform::new(1.0, 2.0).unwrap(), |
613 | Uniform::new(1.0, 2.0).unwrap() |
614 | ); |
615 | |
616 | // To cover UniformInt |
617 | assert_eq!( |
618 | Uniform::new(1_u32, 2_u32).unwrap(), |
619 | Uniform::new(1_u32, 2_u32).unwrap() |
620 | ); |
621 | } |
622 | } |
623 | |