use crate::Numeric;
pub trait RandomSource<T: RandomScalar> {
#[must_use]
fn next_u32(&mut self) -> u32;
#[must_use]
fn next_u64(&mut self) -> u64 {
((self.next_u32() as u64) << 32) | (self.next_u32() as u64)
}
#[must_use]
fn next_unit(&mut self) -> T {
T::next_unit(self)
}
#[must_use]
fn standard_normal(&mut self) -> T {
if let Some(cached) = self.get_cache() {
return cached;
}
loop {
let x_draw = T::TWO * self.next_unit() - T::ONE;
let y_draw = T::TWO * self.next_unit() - T::ONE;
let radius_squared = x_draw.powi(2) + y_draw.powi(2);
if radius_squared > T::ZERO && radius_squared < T::ONE {
let scale = (-T::TWO * radius_squared.ln() / radius_squared).sqrt();
self.set_cache(y_draw * scale);
return x_draw * scale;
}
}
}
fn get_cache(&mut self) -> Option<T>;
fn set_cache(&mut self, value: T);
}
pub trait RandomScalar: Numeric {
#[must_use]
fn next_unit<R: RandomSource<Self> + ?Sized>(source: &mut R) -> Self;
}
impl RandomScalar for f64 {
#[inline]
fn next_unit<R: RandomSource<f64> + ?Sized>(source: &mut R) -> Self {
(source.next_u64() >> 11) as f64 * (1.0 / (1u64 << 53) as f64)
}
}
impl RandomScalar for f32 {
#[inline]
fn next_unit<R: RandomSource<f32> + ?Sized>(source: &mut R) -> Self {
(source.next_u32() >> 8) as f32 * (1.0 / (1u32 << 24) as f32)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Pcg32<T: RandomScalar> {
state: u64,
increment: u64,
cache: Option<T>,
}
impl<T: RandomScalar> Pcg32<T> {
#[must_use]
pub fn new(seed: u64) -> Self {
Self::with_stream(seed, DEFAULT_STREAM)
}
#[must_use]
pub fn with_stream(seed: u64, stream: u64) -> Self {
let mut generator = Pcg32 {
state: 0,
increment: (stream << 1) | 1,
cache: None,
};
let _ = generator.next_u32();
generator.state = generator.state.wrapping_add(seed);
let _ = generator.next_u32();
generator
}
}
impl<T: RandomScalar> RandomSource<T> for Pcg32<T> {
fn next_u32(&mut self) -> u32 {
let previous = self.state;
self.state = previous
.wrapping_mul(PCG_MULTIPLIER)
.wrapping_add(self.increment);
let xorshifted = (((previous >> 18) ^ previous) >> 27) as u32;
let rotation = (previous >> 59) as u32;
xorshifted.rotate_right(rotation)
}
fn set_cache(&mut self, value: T) {
self.cache = Some(value);
}
fn get_cache(&mut self) -> Option<T> {
self.cache.take()
}
}
const PCG_MULTIPLIER: u64 = 6364136223846793005;
const DEFAULT_STREAM: u64 = 0xda3e_39cb_94b9_5bdb;