#[allow(unused_imports)]
use crate::lehmer::Lehmer64;
use crate::traits::{CoreRNG, FloatRNG, SeekableRNG};
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
pub struct WyRand {
state: u64,
}
impl WyRand {
const WY0: u64 = 0x2D35_8DCC_AA6C_78A5;
const WY1: u64 = 0x8BB8_4B93_962E_ACC9;
}
impl CoreRNG for WyRand {
#[inline]
fn new(seed: u64) -> Self {
Self { state: seed }
}
#[allow(clippy::cast_possible_truncation)]
fn next(&mut self) -> u64 {
self.state = self.state.wrapping_add(Self::WY0);
let c = u128::from(self.state).wrapping_mul(u128::from(self.state ^ Self::WY1));
((c >> 64) as u64) ^ (c as u64)
}
}
impl SeekableRNG for WyRand {
#[inline]
fn move_state_forwards(&mut self, delta: u64) {
self.state = self.state.wrapping_add(Self::WY0.wrapping_mul(delta));
}
#[inline]
fn move_state_backwards(&mut self, delta: u64) {
self.state = self.state.wrapping_sub(Self::WY0.wrapping_mul(delta));
}
}
#[cfg(feature = "float")]
impl FloatRNG for WyRand {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_wide_seek() {
let mut prng = WyRand::new(0xDEADBEEF);
let n_one = prng.next();
prng.move_state_forwards(u64::MAX - 2);
prng.move_state_backwards(u64::MAX - 1);
let n_two = prng.next();
assert_eq!(n_one, n_two);
let mut prng = WyRand::new(0xDEADBEEF);
let n_one = prng.next();
prng.move_state_forwards(u64::MAX);
let n_two = prng.next();
assert_eq!(n_one, n_two);
}
}