rand/distr/
uniform.rs

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"]
98mod float;
99#[doc(inline)]
100pub use float::UniformFloat;
101
102#[path = "uniform_int.rs"]
103mod int;
104#[doc(inline)]
105pub use int::{UniformInt, UniformUsize};
106
107#[path = "uniform_other.rs"]
108mod other;
109#[doc(inline)]
110pub use other::{UniformChar, UniformDuration};
111
112use core::fmt;
113use core::ops::{Range, RangeInclusive, RangeTo, RangeToInclusive};
114
115use crate::distr::Distribution;
116use crate::{Rng, RngCore};
117
118/// Error type returned from [`Uniform::new`] and `new_inclusive`.
119#[derive(Clone, Copy, Debug, PartialEq, Eq)]
120pub 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
127impl 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")]
137impl std::error::Error for Error {}
138
139#[cfg(feature = "serde")]
140use 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)]
220pub struct Uniform<X: SampleUniform>(X::Sampler);
221
222impl<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
255impl<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
268pub 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
283pub 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
372impl<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(r.start, r.end)
377    }
378}
379
380impl<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(r.start(), 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
393pub 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}
399impl<Borrowed> SampleBorrow<Borrowed> for Borrowed
400where
401    Borrowed: SampleUniform,
402{
403    #[inline(always)]
404    fn borrow(&self) -> &Borrowed {
405        self
406    }
407}
408impl<Borrowed> SampleBorrow<Borrowed> for &Borrowed
409where
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`.
422pub 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
430impl<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
442impl<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
454macro_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
482impl_sample_range_u!(u8);
483impl_sample_range_u!(u16);
484impl_sample_range_u!(u32);
485impl_sample_range_u!(u64);
486impl_sample_range_u!(u128);
487impl_sample_range_u!(usize);
488
489#[cfg(test)]
490mod 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}