const N: usize = 624;
const M: usize = 397;
const MATRIX_A: u32 = 0x9908_b0df;
const UPPER_MASK: u32 = 0x8000_0000;
const LOWER_MASK: u32 = 0x7fff_ffff;
pub(super) struct MersenneTwister {
mt: [u32; N],
mti: usize,
}
impl MersenneTwister {
pub(super) fn new(seed: u64) -> Self {
let mut mt = [0u32; N];
mt[0] = seed as u32;
for i in 1..N {
mt[i] = 1_812_433_253u32
.wrapping_mul(mt[i - 1] ^ (mt[i - 1] >> 30))
.wrapping_add(i as u32);
}
Self { mt, mti: N }
}
fn twist(&mut self) {
for kk in 0..N {
let y = (self.mt[kk] & UPPER_MASK) | (self.mt[(kk + 1) % N] & LOWER_MASK);
let mag = if y & 1 == 1 { MATRIX_A } else { 0 };
self.mt[kk] = self.mt[(kk + M) % N] ^ (y >> 1) ^ mag;
}
self.mti = 0;
}
pub(super) fn next_u32(&mut self) -> u32 {
if self.mti == N {
self.twist();
}
let mut y = self.mt[self.mti];
self.mti += 1;
y ^= y >> 11;
y ^= (y << 7) & 0x9d2c_5680;
y ^= (y << 15) & 0xefc6_0000;
y ^= y >> 18;
y
}
pub(super) fn next_real(&mut self) -> f64 {
(f64::from(self.next_u32()) + 0.5) / 4_294_967_296.0
}
}
#[cfg(test)]
mod tests {
use super::MersenneTwister;
#[test]
fn matches_reference_mt19937_outputs() {
let mut rng = MersenneTwister::new(5489);
let expected = [
3_499_211_612u32,
581_869_302,
3_890_346_734,
3_586_334_585,
545_404_204,
];
for (i, &e) in expected.iter().enumerate() {
assert_eq!(rng.next_u32(), e, "draw {i}");
}
}
}