devela/num/rand/
xyza8.rs

1// devela::num::rand::xyza8
2//
3//!
4
5use crate::{ConstDefault, Own};
6
7/// A simple 8-bit <abbr title="Pseudo-Random Number Generator">PRNG</abbr>
8/// with 32-bit of state, based on the *XorShift* algorithm.
9///
10/// It has a 0.8% chance of falling into a poor quality short chain,
11/// a some degree of care is required to seed it. However, the quality of the
12/// random numbers is excellent for such a small state (32 bits), and it passes
13/// almost all of the die hard tests.
14///
15/// Its longest cycle is 4_261_412_736.
16// (== u32::MAX + u16::MAX * 512 + 639).
17#[doc = crate::doc_!(vendor: "8bit_rng")]
18#[must_use]
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub struct Xyza8a {
21    x: u8,
22    y: u8,
23    z: u8,
24    a: u8,
25}
26
27/// Creates a new PRNG initialized with the default fixed seed.
28impl Default for Xyza8a {
29    fn default() -> Self {
30        Self::DEFAULT
31    }
32}
33/// Creates a new PRNG initialized with the default fixed seed.
34impl ConstDefault for Xyza8a {
35    const DEFAULT: Self = Self::new(Self::DEFAULT_SEED);
36}
37
38// private associated items
39impl Xyza8a {
40    const DEFAULT_SEED: [u8; 4] = [0xDE, 0xFA, 0x00, 0x17];
41}
42
43impl Xyza8a {
44    /// Returns a seeded `Xyza8a` generator from the given 4 × 8-bit seeds.
45    pub const fn new(seeds: [u8; 4]) -> Self {
46        Self { x: seeds[0], y: seeds[1], z: seeds[2], a: seeds[3] }
47    }
48
49    #[must_use]
50    /// Returns the PRNG's inner state as a raw snapshot.
51    pub const fn inner_state(self) -> [u8; 4] {
52        [self.x, self.y, self.z, self.a]
53    }
54    /// Restores the PRNG from the given state.
55    pub const fn from_state(state: [u8; 4]) -> Self {
56        Self { x: state[0], y: state[1], z: state[2], a: state[3] }
57    }
58
59    #[must_use]
60    /// Returns the current random `u8`.
61    pub const fn current_u8(&self) -> u8 {
62        self.a
63    }
64    /// Advances the state and returns the next random `u8`.
65    pub fn next_u8(&mut self) -> u8 {
66        let t = self.x ^ (self.x << 4);
67        self.x = self.y;
68        self.y = self.z;
69        self.z = self.a;
70        self.a = self.z ^ t ^ (self.z >> 1) ^ (t << 1);
71        self.a
72    }
73
74    /// Returns a copy of the next new random state.
75    pub const fn peek_next_state(&self) -> Self {
76        let mut new = *self;
77
78        let t = new.x ^ (new.x << 4);
79        new.x = new.y;
80        new.y = new.z;
81        new.z = new.a;
82        new.a = new.z ^ t ^ (new.z >> 1) ^ (t << 1);
83        new
84    }
85
86    /// Returns both the next random state and the `u8` value.
87    pub const fn own_next_u8(self) -> Own<Self, u8> {
88        let s = self.peek_next_state();
89        let v = s.current_u8();
90        Own::new(s, v)
91    }
92}
93
94/// # Extra constructors
95impl Xyza8a {
96    /// Returns a seeded `Xyza8a` generator from the given 32-bit seed.
97    ///
98    /// The seeds will be split in little endian order.
99    pub const fn new1_u32(seed: u32) -> Self {
100        Self::new(seed.to_le_bytes())
101    }
102
103    /// Returns a seeded `Xyza8a` generator from the given 2 × 16-bit seeds.
104    ///
105    /// The seeds will be split in little endian order.
106    pub const fn new2_u16(seeds: [u16; 2]) -> Self {
107        let [x, y] = seeds[0].to_le_bytes();
108        let [z, a] = seeds[1].to_le_bytes();
109        Self::new([x, y, z, a])
110    }
111
112    /// Returns a seeded `Xyza8b` generator from the given 4 × 8-bit seeds.
113    /// This is an alias of [`new`][Self#method.new].
114    pub const fn new4_u8(seeds: [u8; 4]) -> Self {
115        Self::new(seeds)
116    }
117}
118
119// -----------------------------------------------------------------------------
120
121/// A simple 8-bit <abbr title="Pseudo-Random Number Generator">PRNG</abbr>
122/// with 32-bit of state, based on the *XorShift* algorithm.
123///
124/// It has an almost optimal cycle so no real care is required
125/// for seeding except avoiding all zeros, but it fails many of the die hard
126/// random number tests.
127///
128/// Its longest cycle is 4,294,967,294.
129#[doc = crate::doc_!(vendor: "8bit_rng")]
130#[derive(Clone, Copy, Debug, PartialEq, Eq)]
131pub struct Xyza8b {
132    x: u8,
133    y: u8,
134    z: u8,
135    a: u8,
136}
137
138impl Default for Xyza8b {
139    fn default() -> Self {
140        Self::DEFAULT
141    }
142}
143impl ConstDefault for Xyza8b {
144    const DEFAULT: Self = Self::new(Self::DEFAULT_SEED);
145}
146
147// private associated items
148impl Xyza8b {
149    const DEFAULT_SEED: [u8; 4] = [0xDE, 0xFA, 0x00, 0x17];
150}
151
152impl Xyza8b {
153    /// Returns a seeded `Xyza8b` generator from the given 4 × 8-bit seeds.
154    /// This is the fastest constructor.
155    pub const fn new(seeds: [u8; 4]) -> Self {
156        Self { x: seeds[0], y: seeds[1], z: seeds[2], a: seeds[3] }
157    }
158
159    #[must_use]
160    /// Returns the PRNG's inner state as a raw snapshot.
161    pub const fn inner_state(self) -> [u8; 4] {
162        [self.x, self.y, self.z, self.a]
163    }
164    /// Restores the PRNG from the given state.
165    pub const fn from_state(state: [u8; 4]) -> Self {
166        Self { x: state[0], y: state[1], z: state[2], a: state[3] }
167    }
168
169    /// Returns the current random `u8`.
170    pub const fn current_u8(&self) -> u8 {
171        self.a
172    }
173
174    /// Returns the next random `u8`.
175    pub fn next_u8(&mut self) -> u8 {
176        let t = self.x ^ (self.x >> 1);
177        self.x = self.y;
178        self.y = self.z;
179        self.z = self.a;
180        self.a = self.z ^ t ^ (self.z >> 3) ^ (t << 1);
181        self.a
182    }
183
184    /// Returns a copy of the next new random state.
185    pub const fn peek_next_state(&self) -> Self {
186        let mut new = *self;
187
188        let t = new.x ^ (new.x >> 1);
189        new.x = new.y;
190        new.y = new.z;
191        new.z = new.a;
192        new.a = new.z ^ t ^ (new.z >> 3) ^ (t << 1);
193        new
194    }
195
196    /// Returns both the next random state and the `u8` value.
197    pub const fn own_next_u8(self) -> Own<Self, u8> {
198        let s = self.peek_next_state();
199        let v = s.current_u8();
200        Own::new(s, v)
201    }
202}
203
204/// # Extra constructors
205impl Xyza8b {
206    /// Returns a seeded `Xyza8a` generator from the given 32-bit seed.
207    ///
208    /// The seeds will be split in little endian order.
209    pub const fn new1_u32(seed: u32) -> Self {
210        Self::new(seed.to_le_bytes())
211    }
212
213    /// Returns a seeded `Xyza8a` generator from the given 2 × 16-bit seeds.
214    ///
215    /// The seeds will be split in little endian order.
216    pub const fn new2_u16(seeds: [u16; 2]) -> Self {
217        let [x, y] = seeds[0].to_le_bytes();
218        let [z, b] = seeds[1].to_le_bytes();
219        Self::new([x, y, z, b])
220    }
221
222    /// Returns a seeded `Xyza8b` generator from the given 4 × 8-bit seeds.
223    /// This is an alias of [`new`][Self#method.new].
224    pub const fn new4_u8(seeds: [u8; 4]) -> Self {
225        Self::new(seeds)
226    }
227}
228
229#[cfg(feature = "dep_rand_core")]
230#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "dep_rand_core")))]
231mod impl_rand {
232    use super::{Xyza8a, Xyza8b};
233    use crate::_dep::rand_core::{RngCore, SeedableRng};
234
235    impl RngCore for Xyza8a {
236        /// Returns the next 4 × random `u8` combined as a single `u32`.
237        fn next_u32(&mut self) -> u32 {
238            u32::from_le_bytes([self.next_u8(), self.next_u8(), self.next_u8(), self.next_u8()])
239        }
240        /// Returns the next 8 × random `u8` combined as a single `u64`.
241        fn next_u64(&mut self) -> u64 {
242            u64::from_le_bytes([
243                self.next_u8(),
244                self.next_u8(),
245                self.next_u8(),
246                self.next_u8(),
247                self.next_u8(),
248                self.next_u8(),
249                self.next_u8(),
250                self.next_u8(),
251            ])
252        }
253        fn fill_bytes(&mut self, dest: &mut [u8]) {
254            for byte in dest {
255                *byte = self.next_u8();
256            }
257        }
258    }
259    impl SeedableRng for Xyza8a {
260        type Seed = [u8; 4];
261        fn from_seed(seeds: Self::Seed) -> Self {
262            Self::new(seeds)
263        }
264    }
265
266    impl RngCore for Xyza8b {
267        /// Returns the next 4 × random `u8` combined as a single `u32`.
268        fn next_u32(&mut self) -> u32 {
269            u32::from_le_bytes([self.next_u8(), self.next_u8(), self.next_u8(), self.next_u8()])
270        }
271        /// Returns the next 8 × random `u8` combined as a single `u64`.
272        fn next_u64(&mut self) -> u64 {
273            u64::from_le_bytes([
274                self.next_u8(),
275                self.next_u8(),
276                self.next_u8(),
277                self.next_u8(),
278                self.next_u8(),
279                self.next_u8(),
280                self.next_u8(),
281                self.next_u8(),
282            ])
283        }
284        fn fill_bytes(&mut self, dest: &mut [u8]) {
285            for byte in dest {
286                *byte = self.next_u8();
287            }
288        }
289    }
290    impl SeedableRng for Xyza8b {
291        type Seed = [u8; 4];
292        fn from_seed(seeds: Self::Seed) -> Self {
293            Self::new(seeds)
294        }
295    }
296}