use crate::{constants::BITS_U64, float::AlpFloat, sampler::BestParams};
pub(crate) const EXP_MASK: u16 = 0x001F;
pub(crate) const FAC_SHIFT: u16 = 5;
pub(crate) const FAC_MASK: u16 = 0x000F;
pub(crate) const BIT_WIDTH_SHIFT: u16 = 9;
pub(crate) const BIT_WIDTH_MASK: u16 = 0x007F;
#[inline(always)]
pub(crate) const fn pack_params(exp: u8, fac: u8, bit_width: u8) -> u16 {
((exp as u16) & EXP_MASK)
| (((fac as u16) & FAC_MASK) << FAC_SHIFT)
| (((bit_width as u16) & BIT_WIDTH_MASK) << BIT_WIDTH_SHIFT)
}
#[inline(always)]
pub(crate) const fn unpack_params(params: u16) -> (u8, u8, u8) {
let exp = (params & EXP_MASK) as u8;
let fac = ((params >> FAC_SHIFT) & FAC_MASK) as u8;
let bit_width = ((params >> BIT_WIDTH_SHIFT) & BIT_WIDTH_MASK) as u8;
(exp, fac, bit_width)
}
#[inline(always)]
pub(crate) const fn bits_needed(max_val: u64) -> u8 {
(u64::BITS - max_val.leading_zeros()) as u8
}
#[inline(always)]
pub(crate) const fn bit_mask(bit_width: u8) -> u64 {
if bit_width >= BITS_U64 as u8 {
u64::MAX
} else {
(1u64 << bit_width).wrapping_sub(1)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct AlpParams {
pub exp: u8,
pub fac: u8,
pub bit_width: u8,
pub use_div: bool,
}
impl AlpParams {
#[inline(always)]
pub const fn new(exp: u8, fac: u8, bit_width: u8, use_div: bool) -> Self {
Self {
exp,
fac,
bit_width,
use_div,
}
}
#[inline(always)]
pub const fn from_best_params(best: BestParams, bit_width: u8) -> Self {
Self {
exp: best.exp,
fac: best.fac,
bit_width,
use_div: best.use_div,
}
}
#[inline(always)]
pub const fn pack(&self) -> u16 {
pack_params(self.exp, self.fac, self.bit_width)
}
#[inline(always)]
pub const fn from_packed(packed: u16, use_div: bool) -> Self {
let (exp, fac, bit_width) = unpack_params(packed);
Self {
exp,
fac,
bit_width,
use_div,
}
}
#[inline(always)]
pub const fn standard_type<F: AlpFloat>(&self) -> u8 {
if self.use_div {
F::TYPE_DEC_BYTE
} else {
F::TYPE_BYTE
}
}
#[inline(always)]
pub const fn delta_type<F: AlpFloat>(&self) -> u8 {
if self.use_div {
F::TYPE_DEC_DELTA_BYTE
} else {
F::TYPE_DELTA_BYTE
}
}
#[inline(always)]
pub const fn validate<F: AlpFloat>(&self) -> bool {
self.exp <= F::MAX_EXPONENT
&& self.fac <= F::MAX_FAC
&& self.fac <= self.exp
&& self.bit_width <= F::MAX_BIT_WIDTH
}
#[inline(always)]
pub fn factors<F: AlpFloat>(&self) -> (F, i64, F) {
(
F::exp_factor(self.exp, self.fac),
F::fac_int(self.fac),
F::frac_exp(self.exp),
)
}
}