use std::num::Wrapping;
const WORD_SIZE: u32 = 32;
const RECURRENCE: i32 = 624;
const MIDDLE_WORD: usize = 397;
const SEPERATION_POINT: u32 = 31;
const RELATIONAL_NORMAL_COEFFICIENT: u32 = 0x9908B0DF;
const TEMPERING_BITMASK_B: u32 = 0x9D2C5680;
const TEMPERING_BITMASK_C: u32 = 0xEFC60000;
const TEMPERING_BITSHIFT_S: u32 = 7;
const TEMPERING_BITSHIFT_T: u32 = 15;
const ADDITIONAL_SHIFT_U: u32 = 11;
const ADDITIONAL_SHIFT_L: u32 = 18;
const MT19937_F: u32 = 1812433253;
const UMASK: u32 = 0xFFFFFFFF << SEPERATION_POINT;
const LMASK: u32 = 0xFFFFFFFF >> (WORD_SIZE - SEPERATION_POINT);
#[derive(Debug, Clone)]
pub struct MarsenneTwister32 {
state_array: [u32; RECURRENCE as usize],
x_sub_k: usize,
}
impl MarsenneTwister32 {
pub fn new(seed: u32) -> Self {
let mut state_array: [u32; RECURRENCE as usize] = [0; RECURRENCE as usize];
state_array[0] = seed;
let mut seed = seed;
for (i, item) in state_array.iter_mut().enumerate().skip(1) {
seed = (Wrapping(MT19937_F) * Wrapping(seed ^ (seed >> (WORD_SIZE - 2)))).0 + i as u32;
*item = seed;
}
Self {
state_array,
x_sub_k: 0,
}
}
pub fn generate(&mut self) -> u32 {
let x_sub_n_min_one: i32 = self.x_sub_k as i32 - (RECURRENCE - 1);
let x_sub_n_min_one = if x_sub_n_min_one < 0 {
x_sub_n_min_one + RECURRENCE
} else {
x_sub_n_min_one
};
let rhs_transformation: u32 = (self.state_array[self.x_sub_k] & UMASK)
| (self.state_array[x_sub_n_min_one as usize] & LMASK);
let x_lower_bit = rhs_transformation & 0b1;
let x_a: u32 = if x_lower_bit == 0 {
rhs_transformation >> 1
} else {
(rhs_transformation >> 1) ^ RELATIONAL_NORMAL_COEFFICIENT
};
let x_sub_n_min_m = self.x_sub_k as i32 - (RECURRENCE - MIDDLE_WORD as i32);
let x_sub_n_min_m = if x_sub_n_min_m < 0 {
x_sub_n_min_m + RECURRENCE
} else {
x_sub_n_min_m
};
let outer_transformation = self.state_array[x_sub_n_min_m as usize] ^ x_a; self.state_array[self.x_sub_k] = outer_transformation;
self.x_sub_k += 1;
if self.x_sub_k >= RECURRENCE as usize {
self.x_sub_k = 0
};
let mut y = outer_transformation ^ (outer_transformation >> ADDITIONAL_SHIFT_U);
y = y ^ ((y << TEMPERING_BITSHIFT_S) & TEMPERING_BITMASK_B);
y = y ^ ((y << TEMPERING_BITSHIFT_T) & TEMPERING_BITMASK_C);
y ^ (y >> ADDITIONAL_SHIFT_L)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_can_generate_first_few_random_numbers_correctly() {
let expected_seq: Vec<u32> = vec![
3992670690, 3823185381, 1358822685, 561383553, 789925284, 170765737, 878579710,
3549516158, 2438360421, 2285257250,
];
let mut rng = MarsenneTwister32::new(12345);
for i in expected_seq {
assert_eq!(rng.generate(), i);
}
}
}