use crate::ziggurat_tables;
#[allow(unused_imports)]
use num_traits::Float; use rand::distr::hidden_export::IntoFloat;
use rand::{Rng, RngExt};
#[cfg(test)]
pub(crate) struct ConstRng(pub(crate) u64);
#[cfg(test)]
impl rand::TryRng for ConstRng {
type Error = rand::rand_core::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
Ok(self.next_u64() as u32)
}
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
Ok(self.0)
}
fn try_fill_bytes(&mut self, _: &mut [u8]) -> Result<(), Self::Error> {
unimplemented!()
}
}
#[inline(always)] pub(crate) fn ziggurat<R: Rng + ?Sized, P, Z>(
rng: &mut R,
symmetric: bool,
x_tab: ziggurat_tables::ZigTable,
f_tab: ziggurat_tables::ZigTable,
mut pdf: P,
mut zero_case: Z,
) -> f64
where
P: FnMut(f64) -> f64,
Z: FnMut(&mut R, f64) -> f64,
{
loop {
let bits = rng.next_u64();
let i = bits as usize & 0xff;
let u = if symmetric {
(bits >> 12).into_float_with_exponent(1) - 3.0
} else {
(bits >> 12).into_float_with_exponent(0) - (1.0 - f64::EPSILON / 2.0)
};
let x = u * x_tab[i];
let test_x = if symmetric { x.abs() } else { x };
if test_x < x_tab[i + 1] {
return x;
}
if i == 0 {
return zero_case(rng, u);
}
if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.random::<f64>() < pdf(x) {
return x;
}
}
}