Skip to main content

devela/num/prob/rand/prng/lcg/
u16.rs

1// devela/src/num/prob/rand/prng/lcg/u16.rs
2//
3//! 16-bit Linear Congruential Generator
4//
5
6use crate::{Cast, ConstInit, Own};
7use crate::{Infallible, InfallibleResult, RandQualities, RandSeedable, RandTry};
8
9#[doc = crate::_tags!(rand)]
10#[doc = concat!["A 16-bit ", crate::_ABBR_LCG!(), " ", crate::_ABBR_PRNG!(), "."]]
11#[doc = crate::_doc_meta!{location("num/prob/rand")}]
12///
13/// Based on original code from Ken Musgrave, 1985, in Graphics Gems II.
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15pub struct Lcg16(u16);
16
17/// Creates a new PRNG initialized with the default fixed seed.
18impl Default for Lcg16 {
19    fn default() -> Self {
20        Self::INIT
21    }
22}
23/// Creates a new PRNG initialized with the default fixed seed.
24impl ConstInit for Lcg16 {
25    const INIT: Self = Self::new(Self::DEFAULT_SEED);
26}
27
28// Constant defaults for the Lcg16
29impl Lcg16 {
30    #[doc(hidden)]
31    pub const DEFAULT_SEED: u16 = 0xDEFA;
32
33    /// Multiplier.
34    const MUL: u16 = 25173;
35    /// Increment.
36    const INC: u16 = 13849;
37    /// Modulus.
38    const MOD: u16 = 65535;
39}
40
41impl Lcg16 {
42    /// Creates a new `Lcg16` instance with the given seed.
43    #[must_use]
44    pub const fn new(seed: u16) -> Self {
45        Self(seed)
46    }
47    /// Reseeds the generator with a new seed.
48    pub const fn reseed(&mut self, seed: u16) {
49        self.0 = seed;
50    }
51    #[must_use]
52    /// Returns the PRNG's inner state as a raw snapshot.
53    pub const fn inner_state(self) -> u16 {
54        self.0
55    }
56    /// Restores the PRNG from the given state.
57    pub const fn from_state(state: u16) -> Self {
58        Self(state)
59    }
60    /// Returns the current seed value.
61    #[must_use]
62    pub const fn current_u16(&self) -> u16 {
63        self.0
64    }
65    /// Advances to the next random `u16` value.
66    #[must_use]
67    pub const fn next_u16(&mut self) -> u16 {
68        self.0 = (Self::MUL.wrapping_mul(self.0).wrapping_add(Self::INC)) & Self::MOD;
69        self.0
70    }
71    /// Returns a copy of the next state of the generator.
72    #[must_use]
73    pub const fn peek_next_state(&self) -> Self {
74        let x = (Self::MUL.wrapping_mul(self.0).wrapping_add(Self::INC)) & Self::MOD;
75        Self(x)
76    }
77    /// Returns both the next state and the `u16` value.
78    pub const fn own_next_u16(self) -> Own<Self, u16> {
79        let s = self.peek_next_state();
80        let v = s.current_u16();
81        Own::new(s, v)
82    }
83    /// Fills the buffer with generated bytes.
84    pub const fn fill_bytes(&mut self, buffer: &mut [u8]) {
85        let mut i = 0;
86        while i < buffer.len() {
87            let random_u16 = self.next_u16();
88            let bytes = random_u16.to_le_bytes();
89            let remaining = buffer.len() - i;
90            if remaining >= 2 {
91                buffer[i] = bytes[0];
92                buffer[i + 1] = bytes[1];
93                i += 2;
94            } else {
95                buffer[i] = bytes[0];
96                i += 1;
97            }
98        }
99    }
100}
101/// # Extras
102impl Lcg16 {
103    /// Returns a seeded `Lcg16` generator from the given 16-bit seed.
104    ///
105    /// This is an alias of [`new`][Self#method.new].
106    pub const fn new1_u16(seed: u16) -> Self {
107        Self::new(seed)
108    }
109    /// Returns a seeded `Lcg16` generator from the given 2 × 8-bit seeds.
110    ///
111    /// The seeds will be joined in little endian order.
112    #[must_use]
113    pub const fn new2_u8(seeds: [u8; 2]) -> Self {
114        Self::new(u16::from_le_bytes(seeds))
115    }
116
117    /// Returns the next 2 × random `u16` combined as a single `u32`.
118    pub const fn next_u32(&mut self) -> u32 {
119        Cast::<u32>::from_u16_le([self.next_u16(), self.next_u16()])
120    }
121    /// Returns the next 4 × random `u16` combined as a single `u64`.
122    pub const fn next_u64(&mut self) -> u64 {
123        Cast::<u64>::from_u16_le([
124            self.next_u16(),
125            self.next_u16(),
126            self.next_u16(),
127            self.next_u16(),
128        ])
129    }
130}
131
132crate::items! {
133    impl RandTry for Lcg16 {
134        type Error = Infallible;
135        const RAND_OUTPUT_BITS: u32 = 64;
136        const RAND_STATE_BITS: u32 = 64;
137        const RAND_QUALITIES: RandQualities = RandQualities::WEAK_PRNG;
138        fn rand_try_next_u16(&mut self) -> InfallibleResult<u16> { Ok(self.next_u16()) }
139        fn rand_try_next_u32(&mut self) -> InfallibleResult<u32> { Ok(self.next_u32()) }
140        fn rand_try_next_u64(&mut self) -> InfallibleResult<u64> { Ok(self.next_u64()) }
141        fn rand_try_fill_bytes(&mut self, buffer: &mut [u8]) -> InfallibleResult<()> {
142            self.fill_bytes(buffer);
143            Ok(())
144        }
145    }
146    impl RandSeedable for Lcg16 {
147        type RandSeed = [u8; 2];
148        #[inline(always)]
149        fn rand_from_seed(seed: Self::RandSeed) -> Self { Self::new(u16::from_le_bytes(seed)) }
150    }
151}
152crate::__impl_dep_rand_core!(Lcg16);