const SPLITMIX64_INCREMENT: u64 = 0x9E37_79B9_7F4A_7C15;
const SPLITMIX64_MUL1: u64 = 0xBF58_476D_1CE4_E5B9;
const SPLITMIX64_MUL2: u64 = 0x94D0_49BB_1331_11EB;
pub(crate) struct SplitMix64 {
state: u64,
}
impl SplitMix64 {
pub(crate) fn new(seed: u64) -> Self {
Self { state: seed }
}
pub(crate) fn next_u64(&mut self) -> u64 {
self.state = self.state.wrapping_add(SPLITMIX64_INCREMENT);
let mut z = self.state;
z = (z ^ (z >> 30)).wrapping_mul(SPLITMIX64_MUL1);
z = (z ^ (z >> 27)).wrapping_mul(SPLITMIX64_MUL2);
z ^ (z >> 31)
}
}
#[cfg(test)]
mod tests {
use super::SplitMix64;
const SPLITMIX64_SEED0_GOLDEN: [u64; 4] = [
0xE220_A839_7B1D_CDAF,
0x6E78_9E6A_A1B9_65F4,
0x06C4_5D18_8009_454F,
0xF88B_B8A8_724C_81EC,
];
const SPLITMIX64_SEED42_GOLDEN: [u64; 4] = [
0xBDD7_3226_2FEB_6E95,
0x28EF_E333_B266_F103,
0x4752_6757_130F_9F52,
0x581C_E1FF_0E4A_E394,
];
#[test]
fn splitmix64_seed0_matches_golden_outputs() {
let mut rng = SplitMix64::new(0);
let actual: Vec<_> = (0..SPLITMIX64_SEED0_GOLDEN.len())
.map(|_| rng.next_u64())
.collect();
assert_eq!(actual, SPLITMIX64_SEED0_GOLDEN);
}
#[test]
fn splitmix64_seed42_matches_golden_outputs() {
let mut rng = SplitMix64::new(42);
let actual: Vec<_> = (0..SPLITMIX64_SEED42_GOLDEN.len())
.map(|_| rng.next_u64())
.collect();
assert_eq!(actual, SPLITMIX64_SEED42_GOLDEN);
}
}