use wrapn::{wrap, wu32};
use crate::prng::b32::SplitMix32;
use crate::rng::Rng;
#[repr(C, align(64))]
#[derive(Debug, Clone, Copy)]
pub struct Xorshift32 {
a: wu32,
}
impl Xorshift32 {
pub const fn new(seed: u32) -> Self {
let mut sm = SplitMix32::new(seed);
Self {
a: wrap!(sm.nextu_const()),
}
}
}
impl Rng for Xorshift32 {
type Word = u32;
#[inline]
fn nextu(&mut self) -> Self::Word {
let x = self.a;
self.a = x ^ (x << 13);
self.a ^= self.a >> 17;
self.a ^= self.a << 5;
*self.a
}
}
#[repr(C, align(64))]
#[derive(Debug, Clone, Copy)]
pub struct Xorshift128 {
x: [wu32; 4],
}
impl Xorshift128 {
pub const fn new(seed: u32) -> Self {
let mut sm = SplitMix32::new(seed);
Self {
x: wrap![
sm.nextu_const(),
sm.nextu_const(),
sm.nextu_const(),
sm.nextu_const()
],
}
}
}
impl Rng for Xorshift128 {
type Word = u32;
#[inline]
fn nextu(&mut self) -> Self::Word {
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]
}
}
#[cfg(feature = "simd")]
pub use simd::*;
#[cfg(feature = "simd")]
pub mod simd {
use std::arch::x86_64::*;
use crate::{RngV, SplitMix32};
const XORSHIFT32X8: usize = 8;
#[repr(C, align(64))]
pub struct Xorshift32x8 {
a: __m256i,
}
impl Xorshift32x8 {
pub fn new(seed: u32) -> Self {
let mut sm = SplitMix32::new(seed);
let mut a = [0u32; XORSHIFT32X8];
for i in 0..XORSHIFT32X8 {
a[i] = sm.nextu_const();
}
unsafe {
Self {
a: _mm256_loadu_epi32(a.as_ptr() as _),
}
}
}
}
impl RngV for Xorshift32x8 {
type Word = __m256i;
#[inline]
fn nextuv(&mut self) -> Self::Word {
unsafe {
let x = self.a;
self.a = _mm256_xor_si256(x, _mm256_slli_epi32::<13>(x));
self.a = _mm256_xor_si256(self.a, _mm256_srli_epi32::<17>(self.a));
self.a = _mm256_xor_si256(self.a, _mm256_slli_epi32::<5>(self.a));
}
self.a
}
}
}
#[cfg(test)]
mod tests {
use super::*;
crate::safe_test! {
Xorshift32,
Xorshift128
}
}