use crate::algos::exp::fixed_d38::exp_fixed;
use crate::algos::ln::fixed_d38::{STRICT_GUARD, ln_fixed};
use crate::algos::fixed_d38::Fixed;
use crate::support::rounding::RoundingMode;
use crate::types::widths::D38;
pub(crate) const INT_FAST_PATH_THRESHOLD: i32 = 64;
#[inline]
fn exp_as_small_int<const SCALE: u32>(exp_raw: i128) -> Option<i32> {
let mult = 10_i128.pow(SCALE);
if exp_raw % mult != 0 {
return None;
}
let q = exp_raw / mult;
if !(i32::MIN as i128..=i32::MAX as i128).contains(&q) {
return None;
}
let n = q as i32;
if n.unsigned_abs() <= INT_FAST_PATH_THRESHOLD as u32 {
Some(n)
} else {
None
}
}
#[inline]
#[must_use]
pub(crate) fn powf_with<const SCALE: u32>(
base: i128,
exp: i128,
working_digits: u32,
mode: RoundingMode,
) -> i128 {
if base <= 0 {
return 0;
}
if let Some(n) = exp_as_small_int::<SCALE>(exp) {
return D38::<SCALE>::from_bits(base).powi(n).to_bits();
}
let w = SCALE + working_digits;
let pow = 10u128.pow(working_digits);
let ln_x = ln_fixed(
Fixed::from_u128_mag(base as u128, false).mul_u128(pow),
w,
);
let y_neg = exp < 0;
let y_w = Fixed::from_u128_mag(exp.unsigned_abs(), false).mul_u128(pow);
let y_w = if y_neg { y_w.neg() } else { y_w };
exp_fixed(y_w.mul(ln_x, w), w)
.round_to_i128_with(w, SCALE, mode)
.unwrap_or_else(|| crate::support::diagnostics::overflow_panic_with_scale("powf kernel", SCALE))
}
#[inline]
#[must_use]
pub(crate) fn powf_strict<const SCALE: u32>(
base: i128,
exp: i128,
mode: RoundingMode,
) -> i128 {
if base <= 0 {
return 0;
}
if let Some(n) = exp_as_small_int::<SCALE>(exp) {
return D38::<SCALE>::from_bits(base).powi(n).to_bits();
}
let w = SCALE + STRICT_GUARD;
let pow = 10u128.pow(STRICT_GUARD);
let ln_x = ln_fixed(
Fixed::from_u128_mag(base as u128, false).mul_u128(pow),
w,
);
let y_neg = exp < 0;
let y_w = Fixed::from_u128_mag(exp.unsigned_abs(), false).mul_u128(pow);
let y_w = if y_neg { y_w.neg() } else { y_w };
exp_fixed(y_w.mul(ln_x, w), w)
.round_to_i128_with(w, SCALE, mode)
.unwrap_or_else(|| crate::support::diagnostics::overflow_panic_with_scale("powf kernel", SCALE))
}