use crate::{Random, Rng};
pub use super::ziggurat_tables::*;
#[inline(always)]
fn into_float_with_exponent(bits: u64, exp: u64) -> f64 {
f64::from_bits(bits >> 12 | (1023 + exp) << 52)
}
#[inline(always)] pub fn ziggurat<R: Rng + ?Sized, P, Z>(
rand: &mut Random<R>,
symmetric: bool,
x_tab: ZigTable,
f_tab: ZigTable,
mut pdf: P,
mut zero_case: Z,
) -> f64
where
P: FnMut(f64) -> f64,
Z: FnMut(&mut Random<R>, f64) -> f64,
{
loop {
let bits = rand.next_u64();
let i = bits as usize & 0xff;
let u = if symmetric {
into_float_with_exponent(bits, 1) - 3.0
} else {
into_float_with_exponent(bits, 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(rand, u);
}
if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rand.float01() < pdf(x) {
return x;
}
}
}