Skip to main content

rand/distr/
uniform_int.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//! `UniformInt` implementation
11
12use super::{Error, SampleBorrow, SampleUniform, UniformSampler};
13use crate::distr::utils::WideningMultiply;
14#[cfg(feature = "simd_support")]
15use crate::distr::{Distribution, StandardUniform};
16use crate::Rng;
17
18#[cfg(feature = "simd_support")]
19use core::simd::prelude::*;
20#[cfg(feature = "simd_support")]
21use core::simd::{LaneCount, SupportedLaneCount};
22
23#[cfg(feature = "serde")]
24use serde::{Deserialize, Serialize};
25
26/// The back-end implementing [`UniformSampler`] for integer types.
27///
28/// Unless you are implementing [`UniformSampler`] for your own type, this type
29/// should not be used directly, use [`Uniform`] instead.
30///
31/// # Implementation notes
32///
33/// For simplicity, we use the same generic struct `UniformInt<X>` for all
34/// integer types `X`. This gives us only one field type, `X`; to store unsigned
35/// values of this size, we take use the fact that these conversions are no-ops.
36///
37/// For a closed range, the number of possible numbers we should generate is
38/// `range = (high - low + 1)`. To avoid bias, we must ensure that the size of
39/// our sample space, `zone`, is a multiple of `range`; other values must be
40/// rejected (by replacing with a new random sample).
41///
42/// As a special case, we use `range = 0` to represent the full range of the
43/// result type (i.e. for `new_inclusive($ty::MIN, $ty::MAX)`).
44///
45/// The optimum `zone` is the largest product of `range` which fits in our
46/// (unsigned) target type. We calculate this by calculating how many numbers we
47/// must reject: `reject = (MAX + 1) % range = (MAX - range + 1) % range`. Any (large)
48/// product of `range` will suffice, thus in `sample_single` we multiply by a
49/// power of 2 via bit-shifting (faster but may cause more rejections).
50///
51/// The smallest integer PRNGs generate is `u32`. For 8- and 16-bit outputs we
52/// use `u32` for our `zone` and samples (because it's not slower and because
53/// it reduces the chance of having to reject a sample). In this case we cannot
54/// store `zone` in the target type since it is too large, however we know
55/// `ints_to_reject < range <= $uty::MAX`.
56///
57/// An alternative to using a modulus is widening multiply: After a widening
58/// multiply by `range`, the result is in the high word. Then comparing the low
59/// word against `zone` makes sure our distribution is uniform.
60///
61/// # Bias
62///
63/// Unless the `unbiased` feature flag is used, outputs may have a small bias.
64/// In the worst case, bias affects 1 in `2^n` samples where n is
65/// 56 (`i8` and `u8`), 48 (`i16` and `u16`), 96 (`i32` and `u32`), 64 (`i64`
66/// and `u64`), 128 (`i128` and `u128`).
67///
68/// [`Uniform`]: super::Uniform
69#[derive(Clone, Copy, Debug, PartialEq, Eq)]
70#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
71pub struct UniformInt<X> {
72    pub(super) low: X,
73    pub(super) range: X,
74    thresh: X, // effectively 2.pow(max(64, uty_bits)) % range
75}
76
77macro_rules! uniform_int_impl {
78    ($ty:ty, $uty:ty, $sample_ty:ident) => {
79        impl UniformInt<$ty> {
80            /// Get the maximum possible value
81            #[allow(unused)]
82            #[inline]
83            pub(crate) fn max(&self) -> $ty {
84                self.range.wrapping_sub(1).wrapping_add(self.low)
85            }
86        }
87
88        impl SampleUniform for $ty {
89            type Sampler = UniformInt<$ty>;
90        }
91
92        impl UniformSampler for UniformInt<$ty> {
93            // We play free and fast with unsigned vs signed here
94            // (when $ty is signed), but that's fine, since the
95            // contract of this macro is for $ty and $uty to be
96            // "bit-equal", so casting between them is a no-op.
97
98            type X = $ty;
99
100            #[inline] // if the range is constant, this helps LLVM to do the
101                      // calculations at compile-time.
102            fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
103            where
104                B1: SampleBorrow<Self::X> + Sized,
105                B2: SampleBorrow<Self::X> + Sized,
106            {
107                let low = *low_b.borrow();
108                let high = *high_b.borrow();
109                if !(low < high) {
110                    return Err(Error::EmptyRange);
111                }
112                UniformSampler::new_inclusive(low, high - 1)
113            }
114
115            #[inline] // if the range is constant, this helps LLVM to do the
116                      // calculations at compile-time.
117            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
118            where
119                B1: SampleBorrow<Self::X> + Sized,
120                B2: SampleBorrow<Self::X> + Sized,
121            {
122                let low = *low_b.borrow();
123                let high = *high_b.borrow();
124                if !(low <= high) {
125                    return Err(Error::EmptyRange);
126                }
127
128                let range = high.wrapping_sub(low).wrapping_add(1) as $uty;
129                let thresh = if range > 0 {
130                    let range = $sample_ty::from(range);
131                    (range.wrapping_neg() % range)
132                } else {
133                    0
134                };
135
136                Ok(UniformInt {
137                    low,
138                    range: range as $ty,           // type: $uty
139                    thresh: thresh as $uty as $ty, // type: $sample_ty
140                })
141            }
142
143            /// Sample from distribution, Lemire's method, unbiased
144            #[inline]
145            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
146                let range = self.range as $uty as $sample_ty;
147                if range == 0 {
148                    return rng.random();
149                }
150
151                let thresh = self.thresh as $uty as $sample_ty;
152                let hi = loop {
153                    let (hi, lo) = rng.random::<$sample_ty>().wmul(range);
154                    if lo >= thresh {
155                        break hi;
156                    }
157                };
158                self.low.wrapping_add(hi as $ty)
159            }
160
161            #[inline]
162            fn sample_single<R: Rng + ?Sized, B1, B2>(
163                low_b: B1,
164                high_b: B2,
165                rng: &mut R,
166            ) -> Result<Self::X, Error>
167            where
168                B1: SampleBorrow<Self::X> + Sized,
169                B2: SampleBorrow<Self::X> + Sized,
170            {
171                let low = *low_b.borrow();
172                let high = *high_b.borrow();
173                if !(low < high) {
174                    return Err(Error::EmptyRange);
175                }
176                Self::sample_single_inclusive(low, high - 1, rng)
177            }
178
179            /// Sample single value, Canon's method, biased
180            ///
181            /// In the worst case, bias affects 1 in `2^n` samples where n is
182            /// 56 (`i8`), 48 (`i16`), 96 (`i32`), 64 (`i64`), 128 (`i128`).
183            #[cfg(not(feature = "unbiased"))]
184            #[inline]
185            fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
186                low_b: B1,
187                high_b: B2,
188                rng: &mut R,
189            ) -> Result<Self::X, Error>
190            where
191                B1: SampleBorrow<Self::X> + Sized,
192                B2: SampleBorrow<Self::X> + Sized,
193            {
194                let low = *low_b.borrow();
195                let high = *high_b.borrow();
196                if !(low <= high) {
197                    return Err(Error::EmptyRange);
198                }
199                let range = high.wrapping_sub(low).wrapping_add(1) as $uty as $sample_ty;
200                if range == 0 {
201                    // Range is MAX+1 (unrepresentable), so we need a special case
202                    return Ok(rng.random());
203                }
204
205                // generate a sample using a sensible integer type
206                let (mut result, lo_order) = rng.random::<$sample_ty>().wmul(range);
207
208                // if the sample is biased...
209                if lo_order > range.wrapping_neg() {
210                    // ...generate a new sample to reduce bias...
211                    let (new_hi_order, _) = (rng.random::<$sample_ty>()).wmul(range as $sample_ty);
212                    // ... incrementing result on overflow
213                    let is_overflow = lo_order.checked_add(new_hi_order as $sample_ty).is_none();
214                    result += is_overflow as $sample_ty;
215                }
216
217                Ok(low.wrapping_add(result as $ty))
218            }
219
220            /// Sample single value, Canon's method, unbiased
221            #[cfg(feature = "unbiased")]
222            #[inline]
223            fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
224                low_b: B1,
225                high_b: B2,
226                rng: &mut R,
227            ) -> Result<Self::X, Error>
228            where
229                B1: SampleBorrow<$ty> + Sized,
230                B2: SampleBorrow<$ty> + Sized,
231            {
232                let low = *low_b.borrow();
233                let high = *high_b.borrow();
234                if !(low <= high) {
235                    return Err(Error::EmptyRange);
236                }
237                let range = high.wrapping_sub(low).wrapping_add(1) as $uty as $sample_ty;
238                if range == 0 {
239                    // Range is MAX+1 (unrepresentable), so we need a special case
240                    return Ok(rng.random());
241                }
242
243                let (mut result, mut lo) = rng.random::<$sample_ty>().wmul(range);
244
245                // In contrast to the biased sampler, we use a loop:
246                while lo > range.wrapping_neg() {
247                    let (new_hi, new_lo) = (rng.random::<$sample_ty>()).wmul(range);
248                    match lo.checked_add(new_hi) {
249                        Some(x) if x < $sample_ty::MAX => {
250                            // Anything less than MAX: last term is 0
251                            break;
252                        }
253                        None => {
254                            // Overflow: last term is 1
255                            result += 1;
256                            break;
257                        }
258                        _ => {
259                            // Unlikely case: must check next sample
260                            lo = new_lo;
261                            continue;
262                        }
263                    }
264                }
265
266                Ok(low.wrapping_add(result as $ty))
267            }
268        }
269    };
270}
271
272uniform_int_impl! { i8, u8, u32 }
273uniform_int_impl! { i16, u16, u32 }
274uniform_int_impl! { i32, u32, u32 }
275uniform_int_impl! { i64, u64, u64 }
276uniform_int_impl! { i128, u128, u128 }
277uniform_int_impl! { u8, u8, u32 }
278uniform_int_impl! { u16, u16, u32 }
279uniform_int_impl! { u32, u32, u32 }
280uniform_int_impl! { u64, u64, u64 }
281uniform_int_impl! { u128, u128, u128 }
282
283#[cfg(feature = "simd_support")]
284macro_rules! uniform_simd_int_impl {
285    ($ty:ident, $unsigned:ident) => {
286        // The "pick the largest zone that can fit in an `u32`" optimization
287        // is less useful here. Multiple lanes complicate things, we don't
288        // know the PRNG's minimal output size, and casting to a larger vector
289        // is generally a bad idea for SIMD performance. The user can still
290        // implement it manually.
291
292        #[cfg(feature = "simd_support")]
293        impl<const LANES: usize> SampleUniform for Simd<$ty, LANES>
294        where
295            LaneCount<LANES>: SupportedLaneCount,
296            Simd<$unsigned, LANES>:
297                WideningMultiply<Output = (Simd<$unsigned, LANES>, Simd<$unsigned, LANES>)>,
298            StandardUniform: Distribution<Simd<$unsigned, LANES>>,
299        {
300            type Sampler = UniformInt<Simd<$ty, LANES>>;
301        }
302
303        #[cfg(feature = "simd_support")]
304        impl<const LANES: usize> UniformSampler for UniformInt<Simd<$ty, LANES>>
305        where
306            LaneCount<LANES>: SupportedLaneCount,
307            Simd<$unsigned, LANES>:
308                WideningMultiply<Output = (Simd<$unsigned, LANES>, Simd<$unsigned, LANES>)>,
309            StandardUniform: Distribution<Simd<$unsigned, LANES>>,
310        {
311            type X = Simd<$ty, LANES>;
312
313            #[inline] // if the range is constant, this helps LLVM to do the
314                      // calculations at compile-time.
315            fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
316                where B1: SampleBorrow<Self::X> + Sized,
317                      B2: SampleBorrow<Self::X> + Sized
318            {
319                let low = *low_b.borrow();
320                let high = *high_b.borrow();
321                if !(low.simd_lt(high).all()) {
322                    return Err(Error::EmptyRange);
323                }
324                UniformSampler::new_inclusive(low, high - Simd::splat(1))
325            }
326
327            #[inline] // if the range is constant, this helps LLVM to do the
328                      // calculations at compile-time.
329            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
330                where B1: SampleBorrow<Self::X> + Sized,
331                      B2: SampleBorrow<Self::X> + Sized
332            {
333                let low = *low_b.borrow();
334                let high = *high_b.borrow();
335                if !(low.simd_le(high).all()) {
336                    return Err(Error::EmptyRange);
337                }
338
339                // NOTE: all `Simd` operations are inherently wrapping,
340                //       see https://doc.rust-lang.org/std/simd/struct.Simd.html
341                let range: Simd<$unsigned, LANES> = ((high - low) + Simd::splat(1)).cast();
342
343                // We must avoid divide-by-zero by using 0 % 1 == 0.
344                let not_full_range = range.simd_gt(Simd::splat(0));
345                let modulo = not_full_range.select(range, Simd::splat(1));
346                let ints_to_reject = range.wrapping_neg() % modulo;
347
348                Ok(UniformInt {
349                    low,
350                    // These are really $unsigned values, but store as $ty:
351                    range: range.cast(),
352                    thresh: ints_to_reject.cast(),
353                })
354            }
355
356            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
357                let range: Simd<$unsigned, LANES> = self.range.cast();
358                let thresh: Simd<$unsigned, LANES> = self.thresh.cast();
359
360                // This might seem very slow, generating a whole new
361                // SIMD vector for every sample rejection. For most uses
362                // though, the chance of rejection is small and provides good
363                // general performance. With multiple lanes, that chance is
364                // multiplied. To mitigate this, we replace only the lanes of
365                // the vector which fail, iteratively reducing the chance of
366                // rejection. The replacement method does however add a little
367                // overhead. Benchmarking or calculating probabilities might
368                // reveal contexts where this replacement method is slower.
369                let mut v: Simd<$unsigned, LANES> = rng.random();
370                loop {
371                    let (hi, lo) = v.wmul(range);
372                    let mask = lo.simd_ge(thresh);
373                    if mask.all() {
374                        let hi: Simd<$ty, LANES> = hi.cast();
375                        // wrapping addition
376                        let result = self.low + hi;
377                        // `select` here compiles to a blend operation
378                        // When `range.eq(0).none()` the compare and blend
379                        // operations are avoided.
380                        let v: Simd<$ty, LANES> = v.cast();
381                        return range.simd_gt(Simd::splat(0)).select(result, v);
382                    }
383                    // Replace only the failing lanes
384                    v = mask.select(v, rng.random());
385                }
386            }
387        }
388    };
389
390    // bulk implementation
391    ($(($unsigned:ident, $signed:ident)),+) => {
392        $(
393            uniform_simd_int_impl!($unsigned, $unsigned);
394            uniform_simd_int_impl!($signed, $unsigned);
395        )+
396    };
397}
398
399#[cfg(feature = "simd_support")]
400uniform_simd_int_impl! { (u8, i8), (u16, i16), (u32, i32), (u64, i64) }
401
402/// The back-end implementing [`UniformSampler`] for `usize`.
403///
404/// # Implementation notes
405///
406/// Sampling a `usize` value is usually used in relation to the length of an
407/// array or other memory structure, thus it is reasonable to assume that the
408/// vast majority of use-cases will have a maximum size under [`u32::MAX`].
409/// In part to optimise for this use-case, but mostly to ensure that results
410/// are portable across 32-bit and 64-bit architectures (as far as is possible),
411/// this implementation will use 32-bit sampling when possible.
412#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
413#[derive(Clone, Copy, Debug, PartialEq, Eq)]
414#[cfg_attr(all(feature = "serde"), derive(Serialize))]
415// To be able to deserialize on 32-bit we need to replace this with a custom
416// implementation of the Deserialize trait, to be able to:
417// - panic when `mode64` is `true` on 32-bit,
418// - assign the default value to `mode64` when it's missing on 64-bit,
419// - panic when the `usize` fields are greater than `u32::MAX` on 32-bit.
420#[cfg_attr(
421    all(feature = "serde", target_pointer_width = "64"),
422    derive(Deserialize)
423)]
424pub struct UniformUsize {
425    /// The lowest possible value.
426    low: usize,
427    /// The number of possible values. `0` has a special meaning: all.
428    range: usize,
429    /// Threshold used when sampling to obtain a uniform distribution.
430    thresh: usize,
431    /// Whether the largest possible value is greater than `u32::MAX`.
432    #[cfg(target_pointer_width = "64")]
433    // Handle missing field when deserializing on 64-bit an object serialized
434    // on 32-bit. Can be removed when switching to a custom deserializer.
435    #[cfg_attr(feature = "serde", serde(default))]
436    mode64: bool,
437}
438
439#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
440impl SampleUniform for usize {
441    type Sampler = UniformUsize;
442}
443
444#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
445impl UniformSampler for UniformUsize {
446    type X = usize;
447
448    #[inline] // if the range is constant, this helps LLVM to do the
449              // calculations at compile-time.
450    fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
451    where
452        B1: SampleBorrow<Self::X> + Sized,
453        B2: SampleBorrow<Self::X> + Sized,
454    {
455        let low = *low_b.borrow();
456        let high = *high_b.borrow();
457        if !(low < high) {
458            return Err(Error::EmptyRange);
459        }
460
461        UniformSampler::new_inclusive(low, high - 1)
462    }
463
464    #[inline] // if the range is constant, this helps LLVM to do the
465              // calculations at compile-time.
466    fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
467    where
468        B1: SampleBorrow<Self::X> + Sized,
469        B2: SampleBorrow<Self::X> + Sized,
470    {
471        let low = *low_b.borrow();
472        let high = *high_b.borrow();
473        if !(low <= high) {
474            return Err(Error::EmptyRange);
475        }
476
477        #[cfg(target_pointer_width = "64")]
478        let mode64 = high > (u32::MAX as usize);
479        #[cfg(target_pointer_width = "32")]
480        let mode64 = false;
481
482        let (range, thresh);
483        if cfg!(target_pointer_width = "64") && !mode64 {
484            let range32 = (high as u32).wrapping_sub(low as u32).wrapping_add(1);
485            range = range32 as usize;
486            thresh = if range32 > 0 {
487                (range32.wrapping_neg() % range32) as usize
488            } else {
489                0
490            };
491        } else {
492            range = high.wrapping_sub(low).wrapping_add(1);
493            thresh = if range > 0 {
494                range.wrapping_neg() % range
495            } else {
496                0
497            };
498        }
499
500        Ok(UniformUsize {
501            low,
502            range,
503            thresh,
504            #[cfg(target_pointer_width = "64")]
505            mode64,
506        })
507    }
508
509    #[inline]
510    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
511        #[cfg(target_pointer_width = "32")]
512        let mode32 = true;
513        #[cfg(target_pointer_width = "64")]
514        let mode32 = !self.mode64;
515
516        if mode32 {
517            let range = self.range as u32;
518            if range == 0 {
519                return rng.random::<u32>() as usize;
520            }
521
522            let thresh = self.thresh as u32;
523            let hi = loop {
524                let (hi, lo) = rng.random::<u32>().wmul(range);
525                if lo >= thresh {
526                    break hi;
527                }
528            };
529            self.low.wrapping_add(hi as usize)
530        } else {
531            let range = self.range as u64;
532            if range == 0 {
533                return rng.random::<u64>() as usize;
534            }
535
536            let thresh = self.thresh as u64;
537            let hi = loop {
538                let (hi, lo) = rng.random::<u64>().wmul(range);
539                if lo >= thresh {
540                    break hi;
541                }
542            };
543            self.low.wrapping_add(hi as usize)
544        }
545    }
546
547    #[inline]
548    fn sample_single<R: Rng + ?Sized, B1, B2>(
549        low_b: B1,
550        high_b: B2,
551        rng: &mut R,
552    ) -> Result<Self::X, Error>
553    where
554        B1: SampleBorrow<Self::X> + Sized,
555        B2: SampleBorrow<Self::X> + Sized,
556    {
557        let low = *low_b.borrow();
558        let high = *high_b.borrow();
559        if !(low < high) {
560            return Err(Error::EmptyRange);
561        }
562
563        if cfg!(target_pointer_width = "64") && high > (u32::MAX as usize) {
564            return UniformInt::<u64>::sample_single(low as u64, high as u64, rng)
565                .map(|x| x as usize);
566        }
567
568        UniformInt::<u32>::sample_single(low as u32, high as u32, rng).map(|x| x as usize)
569    }
570
571    #[inline]
572    fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
573        low_b: B1,
574        high_b: B2,
575        rng: &mut R,
576    ) -> Result<Self::X, Error>
577    where
578        B1: SampleBorrow<Self::X> + Sized,
579        B2: SampleBorrow<Self::X> + Sized,
580    {
581        let low = *low_b.borrow();
582        let high = *high_b.borrow();
583        if !(low <= high) {
584            return Err(Error::EmptyRange);
585        }
586
587        if cfg!(target_pointer_width = "64") && high > (u32::MAX as usize) {
588            return UniformInt::<u64>::sample_single_inclusive(low as u64, high as u64, rng)
589                .map(|x| x as usize);
590        }
591
592        UniformInt::<u32>::sample_single_inclusive(low as u32, high as u32, rng).map(|x| x as usize)
593    }
594}
595
596#[cfg(test)]
597mod tests {
598    use super::*;
599    use crate::distr::{Distribution, Uniform};
600    use core::fmt::Debug;
601    use core::ops::Add;
602
603    #[test]
604    fn test_uniform_bad_limits_equal_int() {
605        assert_eq!(Uniform::new(10, 10), Err(Error::EmptyRange));
606    }
607
608    #[test]
609    fn test_uniform_good_limits_equal_int() {
610        let mut rng = crate::test::rng(804);
611        let dist = Uniform::new_inclusive(10, 10).unwrap();
612        for _ in 0..20 {
613            assert_eq!(rng.sample(dist), 10);
614        }
615    }
616
617    #[test]
618    fn test_uniform_bad_limits_flipped_int() {
619        assert_eq!(Uniform::new(10, 5), Err(Error::EmptyRange));
620    }
621
622    #[test]
623    #[cfg_attr(miri, ignore)] // Miri is too slow
624    fn test_integers() {
625        let mut rng = crate::test::rng(251);
626        macro_rules! t {
627            ($ty:ident, $v:expr, $le:expr, $lt:expr) => {{
628                for &(low, high) in $v.iter() {
629                    let my_uniform = Uniform::new(low, high).unwrap();
630                    for _ in 0..1000 {
631                        let v: $ty = rng.sample(my_uniform);
632                        assert!($le(low, v) && $lt(v, high));
633                    }
634
635                    let my_uniform = Uniform::new_inclusive(low, high).unwrap();
636                    for _ in 0..1000 {
637                        let v: $ty = rng.sample(my_uniform);
638                        assert!($le(low, v) && $le(v, high));
639                    }
640
641                    let my_uniform = Uniform::new(&low, high).unwrap();
642                    for _ in 0..1000 {
643                        let v: $ty = rng.sample(my_uniform);
644                        assert!($le(low, v) && $lt(v, high));
645                    }
646
647                    let my_uniform = Uniform::new_inclusive(&low, &high).unwrap();
648                    for _ in 0..1000 {
649                        let v: $ty = rng.sample(my_uniform);
650                        assert!($le(low, v) && $le(v, high));
651                    }
652
653                    for _ in 0..1000 {
654                        let v = <$ty as SampleUniform>::Sampler::sample_single(low, high, &mut rng).unwrap();
655                        assert!($le(low, v) && $lt(v, high));
656                    }
657
658                    for _ in 0..1000 {
659                        let v = <$ty as SampleUniform>::Sampler::sample_single_inclusive(low, high, &mut rng).unwrap();
660                        assert!($le(low, v) && $le(v, high));
661                    }
662                }
663            }};
664
665            // scalar bulk
666            ($($ty:ident),*) => {{
667                $(t!(
668                    $ty,
669                    [(0, 10), (10, 127), ($ty::MIN, $ty::MAX)],
670                    |x, y| x <= y,
671                    |x, y| x < y
672                );)*
673            }};
674
675            // simd bulk
676            ($($ty:ident),* => $scalar:ident) => {{
677                $(t!(
678                    $ty,
679                    [
680                        ($ty::splat(0), $ty::splat(10)),
681                        ($ty::splat(10), $ty::splat(127)),
682                        ($ty::splat($scalar::MIN), $ty::splat($scalar::MAX)),
683                    ],
684                    |x: $ty, y| x.simd_le(y).all(),
685                    |x: $ty, y| x.simd_lt(y).all()
686                );)*
687            }};
688        }
689        t!(i8, i16, i32, i64, i128, u8, u16, u32, u64, usize, u128);
690
691        #[cfg(feature = "simd_support")]
692        {
693            t!(u8x4, u8x8, u8x16, u8x32, u8x64 => u8);
694            t!(i8x4, i8x8, i8x16, i8x32, i8x64 => i8);
695            t!(u16x2, u16x4, u16x8, u16x16, u16x32 => u16);
696            t!(i16x2, i16x4, i16x8, i16x16, i16x32 => i16);
697            t!(u32x2, u32x4, u32x8, u32x16 => u32);
698            t!(i32x2, i32x4, i32x8, i32x16 => i32);
699            t!(u64x2, u64x4, u64x8 => u64);
700            t!(i64x2, i64x4, i64x8 => i64);
701        }
702    }
703
704    #[test]
705    fn test_uniform_from_std_range() {
706        let r = Uniform::try_from(2u32..7).unwrap();
707        assert_eq!(r.0.low, 2);
708        assert_eq!(r.0.range, 5);
709        assert_eq!(r.0.max(), 6);
710    }
711
712    #[test]
713    fn test_uniform_from_std_range_bad_limits() {
714        #![allow(clippy::reversed_empty_ranges)]
715        assert!(Uniform::try_from(100..10).is_err());
716        assert!(Uniform::try_from(100..100).is_err());
717    }
718
719    #[test]
720    fn test_uniform_from_std_range_inclusive() {
721        let r = Uniform::try_from(2u32..=6).unwrap();
722        assert_eq!(r.0.low, 2);
723        assert_eq!(r.0.range, 5);
724        assert_eq!(r.0.max(), 6);
725    }
726
727    #[test]
728    fn test_uniform_from_std_range_inclusive_bad_limits() {
729        #![allow(clippy::reversed_empty_ranges)]
730        assert!(Uniform::try_from(100..=10).is_err());
731        assert!(Uniform::try_from(100..=99).is_err());
732    }
733
734    #[test]
735    fn value_stability() {
736        fn test_samples<T: SampleUniform + Copy + Debug + PartialEq + Add<T>>(
737            lb: T,
738            ub: T,
739            ub_excl: T,
740            expected: &[T],
741        ) where
742            Uniform<T>: Distribution<T>,
743        {
744            let mut rng = crate::test::rng(897);
745            let mut buf = [lb; 6];
746
747            for x in &mut buf[0..3] {
748                *x = T::Sampler::sample_single_inclusive(lb, ub, &mut rng).unwrap();
749            }
750
751            let distr = Uniform::new_inclusive(lb, ub).unwrap();
752            for x in &mut buf[3..6] {
753                *x = rng.sample(&distr);
754            }
755            assert_eq!(&buf, expected);
756
757            let mut rng = crate::test::rng(897);
758
759            for x in &mut buf[0..3] {
760                *x = T::Sampler::sample_single(lb, ub_excl, &mut rng).unwrap();
761            }
762
763            let distr = Uniform::new(lb, ub_excl).unwrap();
764            for x in &mut buf[3..6] {
765                *x = rng.sample(&distr);
766            }
767            assert_eq!(&buf, expected);
768        }
769
770        test_samples(-105i8, 111, 112, &[-99, -48, 107, 72, -19, 56]);
771        test_samples(2i16, 1352, 1353, &[43, 361, 1325, 1109, 539, 1005]);
772        test_samples(
773            -313853i32,
774            13513,
775            13514,
776            &[-303803, -226673, 6912, -45605, -183505, -70668],
777        );
778        test_samples(
779            131521i64,
780            6542165,
781            6542166,
782            &[1838724, 5384489, 4893692, 3712948, 3951509, 4094926],
783        );
784        test_samples(
785            -0x8000_0000_0000_0000_0000_0000_0000_0000i128,
786            -1,
787            0,
788            &[
789                -30725222750250982319765550926688025855,
790                -75088619368053423329503924805178012357,
791                -64950748766625548510467638647674468829,
792                -41794017901603587121582892414659436495,
793                -63623852319608406524605295913876414006,
794                -17404679390297612013597359206379189023,
795            ],
796        );
797        test_samples(11u8, 218, 219, &[17, 66, 214, 181, 93, 165]);
798        test_samples(11u16, 218, 219, &[17, 66, 214, 181, 93, 165]);
799        test_samples(11u32, 218, 219, &[17, 66, 214, 181, 93, 165]);
800        test_samples(11u64, 218, 219, &[66, 181, 165, 127, 134, 139]);
801        test_samples(11u128, 218, 219, &[181, 127, 139, 167, 141, 197]);
802        test_samples(11usize, 218, 219, &[17, 66, 214, 181, 93, 165]);
803
804        #[cfg(feature = "simd_support")]
805        {
806            let lb = Simd::from([11u8, 0, 128, 127]);
807            let ub = Simd::from([218, 254, 254, 254]);
808            let ub_excl = ub + Simd::splat(1);
809            test_samples(
810                lb,
811                ub,
812                ub_excl,
813                &[
814                    Simd::from([13, 5, 237, 130]),
815                    Simd::from([126, 186, 149, 161]),
816                    Simd::from([103, 86, 234, 252]),
817                    Simd::from([35, 18, 225, 231]),
818                    Simd::from([106, 153, 246, 177]),
819                    Simd::from([195, 168, 149, 222]),
820                ],
821            );
822        }
823    }
824
825    #[test]
826    fn test_uniform_usize_empty_range() {
827        assert_eq!(UniformUsize::new(10, 10), Err(Error::EmptyRange));
828        assert!(UniformUsize::new(10, 11).is_ok());
829
830        assert_eq!(UniformUsize::new_inclusive(10, 9), Err(Error::EmptyRange));
831        assert!(UniformUsize::new_inclusive(10, 10).is_ok());
832    }
833
834    #[test]
835    fn test_uniform_usize_constructors() {
836        assert_eq!(
837            UniformUsize::new_inclusive(u32::MAX as usize, u32::MAX as usize),
838            Ok(UniformUsize {
839                low: u32::MAX as usize,
840                range: 1,
841                thresh: 0,
842                #[cfg(target_pointer_width = "64")]
843                mode64: false
844            })
845        );
846        assert_eq!(
847            UniformUsize::new_inclusive(0, u32::MAX as usize),
848            Ok(UniformUsize {
849                low: 0,
850                range: 0,
851                thresh: 0,
852                #[cfg(target_pointer_width = "64")]
853                mode64: false
854            })
855        );
856        #[cfg(target_pointer_width = "64")]
857        assert_eq!(
858            UniformUsize::new_inclusive(0, u32::MAX as usize + 1),
859            Ok(UniformUsize {
860                low: 0,
861                range: u32::MAX as usize + 2,
862                thresh: 1,
863                mode64: true
864            })
865        );
866        #[cfg(target_pointer_width = "64")]
867        assert_eq!(
868            UniformUsize::new_inclusive(u32::MAX as usize, u64::MAX as usize),
869            Ok(UniformUsize {
870                low: u32::MAX as usize,
871                range: u64::MAX as usize - u32::MAX as usize + 1,
872                thresh: u32::MAX as usize,
873                mode64: true
874            })
875        );
876    }
877
878    // This could be run also on 32-bit when deserialization is implemented.
879    #[cfg(all(feature = "serde", target_pointer_width = "64"))]
880    #[test]
881    fn test_uniform_usize_deserialization() {
882        use serde_json;
883        let original = UniformUsize::new_inclusive(10, 100).expect("creation");
884        let serialized = serde_json::to_string(&original).expect("serialization");
885        let deserialized: UniformUsize =
886            serde_json::from_str(&serialized).expect("deserialization");
887        assert_eq!(deserialized, original);
888    }
889
890    #[cfg(all(feature = "serde", target_pointer_width = "64"))]
891    #[test]
892    fn test_uniform_usize_deserialization_from_32bit() {
893        use serde_json;
894        let serialized_on_32bit = r#"{"low":10,"range":91,"thresh":74}"#;
895        let deserialized: UniformUsize =
896            serde_json::from_str(&serialized_on_32bit).expect("deserialization");
897        assert_eq!(
898            deserialized,
899            UniformUsize::new_inclusive(10, 100).expect("creation")
900        );
901    }
902
903    #[cfg(all(feature = "serde", target_pointer_width = "64"))]
904    #[test]
905    fn test_uniform_usize_deserialization_64bit() {
906        use serde_json;
907        let original = UniformUsize::new_inclusive(1, u64::MAX as usize - 1).expect("creation");
908        assert!(original.mode64);
909        let serialized = serde_json::to_string(&original).expect("serialization");
910        let deserialized: UniformUsize =
911            serde_json::from_str(&serialized).expect("deserialization");
912        assert_eq!(deserialized, original);
913    }
914}