use serde::{Deserialize, Serialize};
pub trait Rng {
fn next_f64(&mut self) -> f64;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct SimpleRng {
state: u64,
}
impl SimpleRng {
#[must_use]
pub fn new(seed: u64) -> Self {
Self {
state: if seed == 0 { 1 } else { seed },
}
}
}
impl Rng for SimpleRng {
#[inline]
fn next_f64(&mut self) -> f64 {
let mut x = self.state;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
self.state = x;
(x >> 11) as f64 / (1u64 << 53) as f64
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_rng_deterministic() {
let mut a = SimpleRng::new(42);
let mut b = SimpleRng::new(42);
for _ in 0..100 {
assert_eq!(a.next_f64().to_bits(), b.next_f64().to_bits());
}
}
#[test]
fn simple_rng_range() {
let mut rng = SimpleRng::new(12345);
for _ in 0..10_000 {
let v = rng.next_f64();
assert!((0.0..1.0).contains(&v), "value out of range: {v}");
}
}
#[test]
fn simple_rng_zero_seed() {
let mut rng = SimpleRng::new(0);
let v = rng.next_f64();
assert!(v >= 0.0);
}
#[test]
fn serde_roundtrip() {
let rng = SimpleRng::new(42);
let json = serde_json::to_string(&rng).unwrap();
let rng2: SimpleRng = serde_json::from_str(&json).unwrap();
assert_eq!(rng.state, rng2.state);
}
}