#[derive(Debug, Clone)]
pub(crate) struct Rng {
state: u64,
}
impl Default for Rng {
fn default() -> Self {
Self::new(crate::clock::now_ns())
}
}
impl Rng {
pub(crate) fn new(seed: u64) -> Self {
Self {
state: seed ^ 0x9E37_79B9_7F4A_7C15,
}
}
pub(crate) fn next_u64(&mut self) -> u64 {
self.state = self.state.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = self.state;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
}
pub(crate) fn below(draw: u64, n: u64) -> u64 {
if n <= 1 {
return 0;
}
((u128::from(draw) * u128::from(n)) >> 64) as u64
}
#[cfg(test)]
mod tests {
use super::Rng;
#[test]
fn the_stream_advances() {
let mut r = Rng::new(42);
let a = r.next_u64();
let b = r.next_u64();
assert_ne!(a, b, "a generator that returns the same draw twice is a constant");
}
#[test]
fn below_is_uniform_and_in_range() {
let mut r = Rng::new(1);
let mut seen = [0usize; 7];
for _ in 0..7000 {
let v = super::below(r.next_u64(), 7) as usize;
assert!(v < 7);
seen[v] += 1;
}
for c in seen {
assert!(c > 800 && c < 1200, "{seen:?}");
}
}
#[test]
fn below_0_and_1_collapse_to_0() {
assert_eq!(super::below(u64::MAX, 0), 0);
assert_eq!(super::below(u64::MAX, 1), 0);
}
}