rand/distributions/
integer.rs

1// Copyright 2018 Developers of the Rand project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! The implementations of the `Standard` distribution for integer types.
10
11use crate::distributions::{Distribution, Standard};
12use crate::Rng;
13#[cfg(all(target_arch = "x86", feature = "simd_support"))]
14use core::arch::x86::{__m128i, __m256i};
15#[cfg(all(target_arch = "x86_64", feature = "simd_support"))]
16use core::arch::x86_64::{__m128i, __m256i};
17#[cfg(not(target_os = "emscripten"))] use core::num::NonZeroU128;
18use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
19#[cfg(feature = "simd_support")] use packed_simd::*;
20
21impl Distribution<u8> for Standard {
22    #[inline]
23    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
24        rng.next_u32() as u8
25    }
26}
27
28impl Distribution<u16> for Standard {
29    #[inline]
30    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u16 {
31        rng.next_u32() as u16
32    }
33}
34
35impl Distribution<u32> for Standard {
36    #[inline]
37    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u32 {
38        rng.next_u32()
39    }
40}
41
42impl Distribution<u64> for Standard {
43    #[inline]
44    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
45        rng.next_u64()
46    }
47}
48
49#[cfg(not(target_os = "emscripten"))]
50impl Distribution<u128> for Standard {
51    #[inline]
52    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u128 {
53        // Use LE; we explicitly generate one value before the next.
54        let x = u128::from(rng.next_u64());
55        let y = u128::from(rng.next_u64());
56        (y << 64) | x
57    }
58}
59
60impl Distribution<usize> for Standard {
61    #[inline]
62    #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))]
63    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
64        rng.next_u32() as usize
65    }
66
67    #[inline]
68    #[cfg(target_pointer_width = "64")]
69    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
70        rng.next_u64() as usize
71    }
72}
73
74macro_rules! impl_int_from_uint {
75    ($ty:ty, $uty:ty) => {
76        impl Distribution<$ty> for Standard {
77            #[inline]
78            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty {
79                rng.gen::<$uty>() as $ty
80            }
81        }
82    };
83}
84
85impl_int_from_uint! { i8, u8 }
86impl_int_from_uint! { i16, u16 }
87impl_int_from_uint! { i32, u32 }
88impl_int_from_uint! { i64, u64 }
89#[cfg(not(target_os = "emscripten"))]
90impl_int_from_uint! { i128, u128 }
91impl_int_from_uint! { isize, usize }
92
93macro_rules! impl_nzint {
94    ($ty:ty, $new:path) => {
95        impl Distribution<$ty> for Standard {
96            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty {
97                loop {
98                    if let Some(nz) = $new(rng.gen()) {
99                        break nz;
100                    }
101                }
102            }
103        }
104    };
105}
106
107impl_nzint!(NonZeroU8, NonZeroU8::new);
108impl_nzint!(NonZeroU16, NonZeroU16::new);
109impl_nzint!(NonZeroU32, NonZeroU32::new);
110impl_nzint!(NonZeroU64, NonZeroU64::new);
111#[cfg(not(target_os = "emscripten"))]
112impl_nzint!(NonZeroU128, NonZeroU128::new);
113impl_nzint!(NonZeroUsize, NonZeroUsize::new);
114
115#[cfg(feature = "simd_support")]
116macro_rules! simd_impl {
117    ($(($intrinsic:ident, $vec:ty),)+) => {$(
118        impl Distribution<$intrinsic> for Standard {
119            #[inline]
120            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $intrinsic {
121                $intrinsic::from_bits(rng.gen::<$vec>())
122            }
123        }
124    )+};
125
126    ($bits:expr,) => {};
127    ($bits:expr, $ty:ty, $($ty_more:ty,)*) => {
128        simd_impl!($bits, $($ty_more,)*);
129
130        impl Distribution<$ty> for Standard {
131            #[inline]
132            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty {
133                let mut vec: $ty = Default::default();
134                unsafe {
135                    let ptr = &mut vec;
136                    let b_ptr = &mut *(ptr as *mut $ty as *mut [u8; $bits/8]);
137                    rng.fill_bytes(b_ptr);
138                }
139                vec.to_le()
140            }
141        }
142    };
143}
144
145#[cfg(feature = "simd_support")]
146simd_impl!(16, u8x2, i8x2,);
147#[cfg(feature = "simd_support")]
148simd_impl!(32, u8x4, i8x4, u16x2, i16x2,);
149#[cfg(feature = "simd_support")]
150simd_impl!(64, u8x8, i8x8, u16x4, i16x4, u32x2, i32x2,);
151#[cfg(feature = "simd_support")]
152simd_impl!(128, u8x16, i8x16, u16x8, i16x8, u32x4, i32x4, u64x2, i64x2,);
153#[cfg(feature = "simd_support")]
154simd_impl!(256, u8x32, i8x32, u16x16, i16x16, u32x8, i32x8, u64x4, i64x4,);
155#[cfg(feature = "simd_support")]
156simd_impl!(512, u8x64, i8x64, u16x32, i16x32, u32x16, i32x16, u64x8, i64x8,);
157#[cfg(all(
158    feature = "simd_support",
159    any(target_arch = "x86", target_arch = "x86_64")
160))]
161simd_impl!((__m128i, u8x16), (__m256i, u8x32),);
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166
167    #[test]
168    fn test_integers() {
169        let mut rng = crate::test::rng(806);
170
171        rng.sample::<isize, _>(Standard);
172        rng.sample::<i8, _>(Standard);
173        rng.sample::<i16, _>(Standard);
174        rng.sample::<i32, _>(Standard);
175        rng.sample::<i64, _>(Standard);
176        #[cfg(not(target_os = "emscripten"))]
177        rng.sample::<i128, _>(Standard);
178
179        rng.sample::<usize, _>(Standard);
180        rng.sample::<u8, _>(Standard);
181        rng.sample::<u16, _>(Standard);
182        rng.sample::<u32, _>(Standard);
183        rng.sample::<u64, _>(Standard);
184        #[cfg(not(target_os = "emscripten"))]
185        rng.sample::<u128, _>(Standard);
186    }
187
188    #[test]
189    fn value_stability() {
190        fn test_samples<T: Copy + core::fmt::Debug + PartialEq>(zero: T, expected: &[T])
191        where Standard: Distribution<T> {
192            let mut rng = crate::test::rng(807);
193            let mut buf = [zero; 3];
194            for x in &mut buf {
195                *x = rng.sample(Standard);
196            }
197            assert_eq!(&buf, expected);
198        }
199
200        test_samples(0u8, &[9, 247, 111]);
201        test_samples(0u16, &[32265, 42999, 38255]);
202        test_samples(0u32, &[2220326409, 2575017975, 2018088303]);
203        test_samples(0u64, &[
204            11059617991457472009,
205            16096616328739788143,
206            1487364411147516184,
207        ]);
208        test_samples(0u128, &[
209            296930161868957086625409848350820761097,
210            145644820879247630242265036535529306392,
211            111087889832015897993126088499035356354,
212        ]);
213        #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))]
214        test_samples(0usize, &[2220326409, 2575017975, 2018088303]);
215        #[cfg(target_pointer_width = "64")]
216        test_samples(0usize, &[
217            11059617991457472009,
218            16096616328739788143,
219            1487364411147516184,
220        ]);
221
222        test_samples(0i8, &[9, -9, 111]);
223        // Skip further i* types: they are simple reinterpretation of u* samples
224
225        #[cfg(feature = "simd_support")]
226        {
227            // We only test a sub-set of types here and make assumptions about the rest.
228
229            test_samples(u8x2::default(), &[
230                u8x2::new(9, 126),
231                u8x2::new(247, 167),
232                u8x2::new(111, 149),
233            ]);
234            test_samples(u8x4::default(), &[
235                u8x4::new(9, 126, 87, 132),
236                u8x4::new(247, 167, 123, 153),
237                u8x4::new(111, 149, 73, 120),
238            ]);
239            test_samples(u8x8::default(), &[
240                u8x8::new(9, 126, 87, 132, 247, 167, 123, 153),
241                u8x8::new(111, 149, 73, 120, 68, 171, 98, 223),
242                u8x8::new(24, 121, 1, 50, 13, 46, 164, 20),
243            ]);
244
245            test_samples(i64x8::default(), &[
246                i64x8::new(
247                    -7387126082252079607,
248                    -2350127744969763473,
249                    1487364411147516184,
250                    7895421560427121838,
251                    602190064936008898,
252                    6022086574635100741,
253                    -5080089175222015595,
254                    -4066367846667249123,
255                ),
256                i64x8::new(
257                    9180885022207963908,
258                    3095981199532211089,
259                    6586075293021332726,
260                    419343203796414657,
261                    3186951873057035255,
262                    5287129228749947252,
263                    444726432079249540,
264                    -1587028029513790706,
265                ),
266                i64x8::new(
267                    6075236523189346388,
268                    1351763722368165432,
269                    -6192309979959753740,
270                    -7697775502176768592,
271                    -4482022114172078123,
272                    7522501477800909500,
273                    -1837258847956201231,
274                    -586926753024886735,
275                ),
276            ]);
277        }
278    }
279}