| 1 | // Copyright 2018-2023 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 xorshift random number generator. |
| 10 | //! |
| 11 | //! # Example |
| 12 | //! |
| 13 | //! To initialize a generator, use the [`SeedableRng`][rand_core::SeedableRng] trait: |
| 14 | //! |
| 15 | //! ``` |
| 16 | //! use rand_core::{SeedableRng, RngCore}; |
| 17 | //! use rand_xorshift::XorShiftRng; |
| 18 | //! |
| 19 | //! let mut rng = XorShiftRng::seed_from_u64(0); |
| 20 | //! let x = rng.next_u32(); |
| 21 | //! ``` |
| 22 | |
| 23 | #![doc ( |
| 24 | html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png" , |
| 25 | html_favicon_url = "https://www.rust-lang.org/favicon.ico" , |
| 26 | html_root_url = "https://docs.rs/rand_xorshift/0.4.0" |
| 27 | )] |
| 28 | #![forbid (unsafe_code)] |
| 29 | #![deny (missing_docs)] |
| 30 | #![deny (missing_debug_implementations)] |
| 31 | #![no_std ] |
| 32 | |
| 33 | use core::fmt; |
| 34 | use core::num::Wrapping as w; |
| 35 | use rand_core::{impls, le, RngCore, SeedableRng, TryRngCore}; |
| 36 | #[cfg (feature = "serde" )] |
| 37 | use serde::{Deserialize, Serialize}; |
| 38 | |
| 39 | /// An Xorshift random number generator. |
| 40 | /// |
| 41 | /// The Xorshift[^1] algorithm is not suitable for cryptographic purposes |
| 42 | /// but is very fast. If you do not know for sure that it fits your |
| 43 | /// requirements, use a more secure one such as `StdRng` or `OsRng`. |
| 44 | /// |
| 45 | /// When seeded with zero (i.e. `XorShiftRng::from_seed(0)` is called), this implementation |
| 46 | /// actually uses `0xBAD_5EED_0BAD_5EED_0BAD_5EED_0BAD_5EED` for the seed. This arbitrary value is |
| 47 | /// used because the underlying algorithm can't escape from an all-zero state, and the function is |
| 48 | /// infallible so it can't signal this by returning an error. |
| 49 | /// |
| 50 | /// [^1]: Marsaglia, George (July 2003). |
| 51 | /// ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper). |
| 52 | /// *Journal of Statistical Software*. Vol. 8 (Issue 14). |
| 53 | #[derive(Clone, PartialEq, Eq)] |
| 54 | #[cfg_attr (feature = "serde" , derive(Serialize, Deserialize))] |
| 55 | pub struct XorShiftRng { |
| 56 | x: w<u32>, |
| 57 | y: w<u32>, |
| 58 | z: w<u32>, |
| 59 | w: w<u32>, |
| 60 | } |
| 61 | |
| 62 | // Custom Debug implementation that does not expose the internal state |
| 63 | impl fmt::Debug for XorShiftRng { |
| 64 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 65 | write!(f, "XorShiftRng {{}}" ) |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | impl RngCore for XorShiftRng { |
| 70 | #[inline ] |
| 71 | fn next_u32(&mut self) -> u32 { |
| 72 | // These shifts are taken from the example in the Summary section of |
| 73 | // the paper 'Xorshift RNGs'. (On the bottom of page 5.) |
| 74 | let x = self.x; |
| 75 | let t = x ^ (x << 11); |
| 76 | self.x = self.y; |
| 77 | self.y = self.z; |
| 78 | self.z = self.w; |
| 79 | let w_ = self.w; |
| 80 | self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); |
| 81 | self.w.0 |
| 82 | } |
| 83 | |
| 84 | #[inline ] |
| 85 | fn next_u64(&mut self) -> u64 { |
| 86 | impls::next_u64_via_u32(self) |
| 87 | } |
| 88 | |
| 89 | #[inline ] |
| 90 | fn fill_bytes(&mut self, dest: &mut [u8]) { |
| 91 | impls::fill_bytes_via_next(self, dest) |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | impl SeedableRng for XorShiftRng { |
| 96 | type Seed = [u8; 16]; |
| 97 | |
| 98 | fn from_seed(seed: Self::Seed) -> Self { |
| 99 | let mut seed_u32 = [0u32; 4]; |
| 100 | le::read_u32_into(&seed, &mut seed_u32); |
| 101 | |
| 102 | // Xorshift cannot be seeded with 0 and we cannot return an Error, but |
| 103 | // also do not wish to panic (because a random seed can legitimately be |
| 104 | // 0); our only option is therefore to use a preset value. |
| 105 | if seed_u32 == [0; 4] { |
| 106 | seed_u32 = [0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED]; |
| 107 | } |
| 108 | |
| 109 | XorShiftRng { |
| 110 | x: w(seed_u32[0]), |
| 111 | y: w(seed_u32[1]), |
| 112 | z: w(seed_u32[2]), |
| 113 | w: w(seed_u32[3]), |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | fn from_rng(rng: &mut impl RngCore) -> Self { |
| 118 | let mut b = [0u8; 16]; |
| 119 | loop { |
| 120 | rng.fill_bytes(b.as_mut()); |
| 121 | if b != [0; 16] { |
| 122 | break; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | XorShiftRng { |
| 127 | x: w(u32::from_le_bytes([b[0], b[1], b[2], b[3]])), |
| 128 | y: w(u32::from_le_bytes([b[4], b[5], b[6], b[7]])), |
| 129 | z: w(u32::from_le_bytes([b[8], b[9], b[10], b[11]])), |
| 130 | w: w(u32::from_le_bytes([b[12], b[13], b[14], b[15]])), |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | fn try_from_rng<R: TryRngCore>(rng: &mut R) -> Result<Self, R::Error> { |
| 135 | let mut b = [0u8; 16]; |
| 136 | loop { |
| 137 | rng.try_fill_bytes(b.as_mut())?; |
| 138 | if b != [0; 16] { |
| 139 | break; |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | Ok(XorShiftRng { |
| 144 | x: w(u32::from_le_bytes([b[0], b[1], b[2], b[3]])), |
| 145 | y: w(u32::from_le_bytes([b[4], b[5], b[6], b[7]])), |
| 146 | z: w(u32::from_le_bytes([b[8], b[9], b[10], b[11]])), |
| 147 | w: w(u32::from_le_bytes([b[12], b[13], b[14], b[15]])), |
| 148 | }) |
| 149 | } |
| 150 | } |
| 151 | |