#[derive(Debug, Clone)]
pub struct Prng {
state: u64,
}
impl Prng {
pub fn new(seed: u64) -> Self {
let mut state = seed ^ 0x9E37_79B9_7F4A_7C15;
if state == 0 {
state = 0xDEAD_BEEF_CAFE_F00D;
}
Prng { state }
}
pub fn next_u64(&mut self) -> u64 {
let mut x = self.state;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
self.state = x;
x.wrapping_mul(0x2545_F491_4F6C_DD1D)
}
pub fn below(&mut self, n: usize) -> usize {
assert!(n > 0, "Prng::below requires n > 0");
(self.next_u64() % (n as u64)) as usize
}
pub fn next_f64(&mut self) -> f64 {
(self.next_u64() >> 11) as f64 / ((1u64 << 53) as f64)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deterministic_for_seed() {
let mut a = Prng::new(42);
let mut b = Prng::new(42);
for _ in 0..1000 {
assert_eq!(a.next_u64(), b.next_u64());
}
}
#[test]
fn different_seeds_differ() {
let mut a = Prng::new(1);
let mut b = Prng::new(2);
assert_ne!(a.next_u64(), b.next_u64());
}
#[test]
fn zero_seed_is_usable() {
let mut a = Prng::new(0);
assert_ne!(a.next_u64(), 0);
assert_ne!(a.next_u64(), a.next_u64());
}
#[test]
fn below_in_range() {
let mut r = Prng::new(7);
for _ in 0..10_000 {
let v = r.below(10);
assert!(v < 10);
}
}
#[test]
fn next_f64_in_unit_interval() {
let mut r = Prng::new(99);
for _ in 0..10_000 {
let v = r.next_f64();
assert!((0.0..1.0).contains(&v));
}
}
}