use crate::float::AlpFloat;
#[inline(always)]
fn scan_deltas<F: AlpFloat>(
slice: &[F::Int],
prev: &mut F::Int,
min_delta: &mut F::Int,
max_delta: &mut F::Int,
) {
let (chunks, rem) = slice.as_chunks::<4>();
for chunk in chunks {
let d0 = F::int_sub(chunk[0], *prev);
let d1 = F::int_sub(chunk[1], chunk[0]);
let d2 = F::int_sub(chunk[2], chunk[1]);
let d3 = F::int_sub(chunk[3], chunk[2]);
*prev = chunk[3];
let l_min = d0.min(d1).min(d2.min(d3));
let l_max = d0.max(d1).max(d2.max(d3));
*min_delta = (*min_delta).min(l_min);
*max_delta = (*max_delta).max(l_max);
}
for &curr in rem {
let delta = F::int_sub(curr, *prev);
*min_delta = (*min_delta).min(delta);
*max_delta = (*max_delta).max(delta);
*prev = curr;
}
}
#[inline(always)]
pub(crate) fn delta_range<F: AlpFloat>(first: F::Int, rest: &[F::Int]) -> (F::Int, u8) {
let mut min_delta = F::MAX_INT;
let mut max_delta = F::MIN_INT;
let mut prev = first;
scan_deltas::<F>(rest, &mut prev, &mut min_delta, &mut max_delta);
let delta_bit_width = F::bits_needed(F::calc_range(min_delta, max_delta));
(min_delta, delta_bit_width)
}
#[inline(always)]
pub(crate) fn eval_delta_benefit<F: AlpFloat>(
first: F::Int,
rest: &[F::Int],
for_bit_width: u8,
) -> Option<(F::Int, u8)> {
if rest.is_empty() {
return None;
}
let pre_n = rest.len().min(16);
let mut min_delta = F::MAX_INT;
let mut max_delta = F::MIN_INT;
let mut prev = first;
scan_deltas::<F>(&rest[..pre_n], &mut prev, &mut min_delta, &mut max_delta);
let pre_bw = F::bits_needed(F::calc_range(min_delta, max_delta));
if pre_bw >= for_bit_width {
return None;
}
if pre_n < rest.len() {
scan_deltas::<F>(&rest[pre_n..], &mut prev, &mut min_delta, &mut max_delta);
}
let delta_bit_width = F::bits_needed(F::calc_range(min_delta, max_delta));
if delta_bit_width < for_bit_width {
Some((min_delta, delta_bit_width))
} else {
None
}
}