use std::sync::atomic::{AtomicU64, Ordering};
pub const DEFAULT_SEED: u64 = 0xCAFE_BABE_DEAD_BEEF;
static RNG_STATE: AtomicU64 = AtomicU64::new(DEFAULT_SEED);
#[inline]
pub fn seed(s: u64) {
RNG_STATE.store(s, Ordering::Relaxed);
}
#[inline]
fn next_u64() -> u64 {
let mut z = RNG_STATE
.fetch_add(0x9E37_79B9_7F4A_7C15, Ordering::Relaxed)
.wrapping_add(0x9E37_79B9_7F4A_7C15);
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
#[inline]
pub fn f64() -> f64 {
(next_u64() >> 11) as f64 * (1.0_f64 / (1u64 << 53) as f64)
}
#[inline]
pub fn i64_range(lo: i64, hi: i64) -> i64 {
debug_assert!(lo <= hi);
let range = (hi as u64).wrapping_sub(lo as u64).wrapping_add(1);
if range == 0 {
return next_u64() as i64;
}
let limit = u64::MAX - (u64::MAX % range);
loop {
let v = next_u64();
if v <= limit {
return lo.wrapping_add((v % range) as i64);
}
}
}
#[inline]
pub fn normal(mu: f64, sigma: f64) -> f64 {
if sigma == 0.0 {
return mu;
}
let mut u1 = f64();
while u1 <= f64::MIN_POSITIVE {
u1 = f64();
}
let u2 = f64();
let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos();
mu + sigma * z
}