use std::time::{Duration, SystemTime};
pub struct Prng {
s: [u64; 4],
}
impl Prng {
pub fn new() -> Self {
let seed = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or(Duration::ZERO)
.subsec_nanos() as u64;
Self::from_seed(seed)
}
pub fn from_seed(seed: u64) -> Self {
let mut x = seed;
let mut s = [0; 4];
for v in &mut s {
*v = splitmix64(&mut x);
}
Self { s }
}
pub fn next(&mut self) -> f64 {
let bits = xoshiro256plus(&mut self.s) >> 11;
bits as f64 / (1_u64 << 53) as f64
}
}
fn xoshiro256plus(s: &mut [u64; 4]) -> u64 {
let result = s[0].wrapping_add(s[3]);
let t = s[1] << 17;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = rotl(s[3], 45);
result
}
fn rotl(x: u64, k: i32) -> u64 {
(x << k) | (x >> (64 - k))
}
fn splitmix64(x: &mut u64) -> u64 {
*x = x.wrapping_add(0x9e3779b97f4a7c15);
let mut z = *x;
z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
z ^ (z >> 31)
}