#[allow(unused_imports)]
use super::word::{DecimalWord, HpWord};
#[allow(unused_imports)]
use crate::fixed_point::width::WideInt;
use super::decimal_compute::decimal_compute_neg;
use crate::fixed_point::domains::symbolic::rational::rational_number::OverflowDetected;
#[inline]
pub(super) fn hp_small<C: DecimalWord>(v: u64) -> C::Hp {
<C::Hp>::from_i128(v as i128)
}
#[inline]
pub(super) fn hp_is_negative<C: DecimalWord>(v: &C::Hp) -> bool {
v.words()[v.words().len() - 1] >> 63 == 1
}
#[inline]
pub(super) fn hp_is_zero<C: DecimalWord>(v: &C::Hp) -> bool {
v.words().iter().all(|&w| w == 0)
}
pub(super) fn hp_bit_length<C: DecimalWord>(v: &C::Hp) -> u32 {
for i in (0..v.words().len()).rev() {
if v.words()[i] != 0 {
return i as u32 * 64 + (64 - v.words()[i].leading_zeros());
}
}
0
}
pub(super) fn hp_mul_small<C: DecimalWord>(mut v: C::Hp, m: u64) -> C::Hp {
let mut carry: u128 = 0;
for w in v.words_mut().iter_mut() {
let cur = (*w as u128) * (m as u128) + carry;
*w = cur as u64;
carry = cur >> 64;
}
assert!(carry == 0 && !hp_is_negative::<C>(&v), "decimal exp: working value outside its tier");
v
}
pub(super) fn hp_divmod_small<C: DecimalWord>(mut v: C::Hp, d: u64) -> (C::Hp, u64) {
let mut rem: u128 = 0;
for w in v.words_mut().iter_mut().rev() {
let cur = (rem << 64) | *w as u128;
*w = (cur / d as u128) as u64;
rem = cur % d as u128;
}
(v, rem as u64)
}
pub(super) fn hp_mul_pow10<C: DecimalWord>(mut v: C::Hp, mut e: u32) -> C::Hp {
while e > 0 {
let k = e.min(19);
v = hp_mul_small::<C>(v, 10u64.pow(k));
e -= k;
}
v
}
pub(super) fn hp_div_pow10<C: DecimalWord>(mut v: C::Hp, mut e: u32) -> C::Hp {
while e > 0 {
let k = e.min(19);
v = hp_divmod_small::<C>(v, 10u64.pow(k)).0;
e -= k;
}
v
}
pub(super) fn hp_pow10<C: DecimalWord>(e: u32) -> C::Hp {
hp_mul_pow10::<C>(hp_small::<C>(1), e)
}
pub(super) fn hp_shl<C: DecimalWord>(v: C::Hp, k: u32) -> C::Hp {
let mut out = hp_small::<C>(0);
let (words, bits) = ((k / 64) as usize, k % 64);
let n = v.words().len();
for i in (words..n).rev() {
let lo = v.words()[i - words];
let carry = if bits > 0 && i > words { v.words()[i - words - 1] >> (64 - bits) } else { 0 };
out.words_mut()[i] = if bits > 0 { (lo << bits) | carry } else { lo };
}
out
}
pub(super) fn hp_shr<C: DecimalWord>(v: C::Hp, k: u32) -> C::Hp {
let mut out = hp_small::<C>(0);
let (words, bits) = ((k / 64) as usize, k % 64);
let n = v.words().len();
for i in 0..n.saturating_sub(words) {
let hi = if bits > 0 && i + words + 1 < n { v.words()[i + words + 1] << (64 - bits) } else { 0 };
out.words_mut()[i] = if bits > 0 { (v.words()[i + words] >> bits) | hi } else { v.words()[i + words] };
}
out
}
pub(super) fn hp_to_i128<C: DecimalWord>(v: &C::Hp) -> i128 {
assert!(hp_bit_length::<C>(v) <= 126, "decimal exp: small value out of range");
(v.words()[0] as i128) | ((v.words()[1] as i128) << 64)
}
pub(super) fn hp_mul<C: DecimalWord>(a: C::Hp, b: C::Hp, half: C::Hp) -> C::Hp {
hp_div_pow10::<C>(a * b + half, C::HP_DP)
}
pub(super) fn hp_div_small_round<C: DecimalWord>(v: C::Hp, n: u64) -> C::Hp {
hp_divmod_small::<C>(v + hp_small::<C>(n / 2), n).0
}
pub(super) fn hp_div_round_half_even<C: DecimalWord>(t: C::Hp, e: u32, k: u32) -> C::Hp {
let d = hp_shl::<C>(hp_pow10::<C>(e), k);
let q = hp_shr::<C>(hp_div_pow10::<C>(t, e), k);
let rem = t - hp_mul_pow10::<C>(hp_shl::<C>(q, k), e);
match rem.cmp(&(d - rem)) {
std::cmp::Ordering::Less => q,
std::cmp::Ordering::Greater => q + hp_small::<C>(1),
std::cmp::Ordering::Equal => if q.words()[0] & 1 == 1 { q + hp_small::<C>(1) } else { q },
}
}
pub(super) fn hp_signed_to_compute<C: DecimalWord>(v: C::Hp) -> Result<C, OverflowDetected> {
let negative = hp_is_negative::<C>(&v);
let magnitude = if negative { -v } else { v };
let q = C::hp_to_compute(&hp_div_round_half_even::<C>(magnitude, C::HP_DP - C::DP as u32, 0))?;
Ok(if negative { decimal_compute_neg(q) } else { q })
}