use crate::rng32::SplitMix32;
use crate::{rng::Rng32, wrap};
use std::num::Wrapping;
#[repr(C)]
pub struct Xorshift32 {
a: Wrapping<u32>,
}
impl Xorshift32 {
pub fn new(seed: u32) -> Self {
let mut sm = SplitMix32::new(seed);
Self {
a: wrap!(sm.nextu()),
}
}
}
impl Rng32 for Xorshift32 {
#[inline]
fn nextu(&mut self) -> u32 {
let x = self.a;
self.a = x ^ (x << 13);
self.a ^= self.a >> 17;
self.a ^= self.a << 5;
self.a.0
}
}
#[repr(C)]
pub struct Xorshift128 {
x: [u32; 4],
}
impl Xorshift128 {
pub fn new(seed: u32) -> Self {
let mut sm = SplitMix32::new(seed);
Self {
x: [sm.nextu(), sm.nextu(), sm.nextu(), sm.nextu()],
}
}
}
impl Rng32 for Xorshift128 {
#[inline]
fn nextu(&mut self) -> u32 {
let mut t = self.x[3];
t ^= t << 11;
t ^= t >> 8;
let s = self.x[0];
(self.x[1], self.x[2], self.x[3]) = (s, self.x[1], self.x[2]);
self.x[0] = t ^ s ^ (s >> 19);
self.x[0]
}
}
#[repr(C)]
pub struct Xorwow {
x: [Wrapping<u32>; 5],
c: Wrapping<u32>,
}
impl Xorwow {
pub fn new(seed: u32) -> Self {
let mut sm = SplitMix32::new(seed);
Self {
x: wrap![sm.nextu(), sm.nextu(), sm.nextu(), sm.nextu(), sm.nextu()],
c: wrap!(sm.nextu()),
}
}
}
impl Rng32 for Xorwow {
#[inline]
fn nextu(&mut self) -> u32 {
let mut t = self.x[4];
let s = self.x[0];
self.x[4] = self.x[3];
self.x[3] = self.x[2];
self.x[2] = self.x[1];
self.x[1] = s;
t ^= t >> 2;
t ^= t << 1;
t ^= s ^ (s << 4);
self.x[0] = t;
self.c += wrap!(362437);
(t + self.c).0
}
}
#[cfg(test)]
mod tests {
use super::*;
crate::safe_test!(Xorshift32);
crate::safe_test!(Xorwow);
}