use crate::algos::exp;
use crate::types::widths::{D9, D18, D38};
use crate::support::rounding::RoundingMode;
pub(crate) trait ExpPolicy: Sized {
fn exp_impl(self, mode: RoundingMode) -> Self;
fn exp_with_impl(self, working_digits: u32, mode: RoundingMode) -> Self;
fn exp2_impl(self, mode: RoundingMode) -> Self;
fn exp2_with_impl(self, working_digits: u32, mode: RoundingMode) -> Self;
}
macro_rules! impl_exp_widen {
($T:ident, $exp_strict:path, $exp_with:path) => {
impl<const SCALE: u32> ExpPolicy for $T<SCALE> {
#[inline]
fn exp_impl(self, mode: RoundingMode) -> Self {
$exp_strict(self, mode)
}
#[inline]
fn exp_with_impl(self, working_digits: u32, mode: RoundingMode) -> Self {
$exp_with(self, working_digits, mode)
}
#[inline]
fn exp2_impl(self, mode: RoundingMode) -> Self {
let wide: D38<SCALE> = self.into();
::core::convert::TryInto::try_into(wide.exp2_strict_with(mode))
.unwrap_or_else(|_| crate::support::diagnostics::overflow_panic_with_scale(
concat!(stringify!($T), "::exp2"), SCALE,
))
}
#[inline]
fn exp2_with_impl(self, working_digits: u32, mode: RoundingMode) -> Self {
let wide: D38<SCALE> = self.into();
::core::convert::TryInto::try_into(wide.exp2_approx_with(working_digits, mode))
.unwrap_or_else(|_| crate::support::diagnostics::overflow_panic_with_scale(
concat!(stringify!($T), "::exp2"), SCALE,
))
}
}
};
}
impl_exp_widen!(D9, exp::widen_to_d38::exp_strict_d9, exp::widen_to_d38::exp_with_d9);
impl_exp_widen!(D18, exp::widen_to_d38::exp_strict_d18, exp::widen_to_d38::exp_with_d18);
#[cfg(any(feature = "d57", feature = "wide"))]
impl<const SCALE: u32> ExpPolicy for D38<SCALE> {
#[inline]
fn exp_impl(self, mode: RoundingMode) -> Self {
Self(exp::borrow_d57::exp_strict::<SCALE>(self.0, mode))
}
#[inline]
fn exp_with_impl(self, _working_digits: u32, mode: RoundingMode) -> Self {
Self(exp::borrow_d57::exp_strict::<SCALE>(self.0, mode))
}
#[inline]
fn exp2_impl(self, mode: RoundingMode) -> Self {
Self(exp::borrow_d57::exp2_strict::<SCALE>(self.0, mode))
}
#[inline]
fn exp2_with_impl(self, _working_digits: u32, mode: RoundingMode) -> Self {
Self(exp::borrow_d57::exp2_strict::<SCALE>(self.0, mode))
}
}
#[cfg(not(any(feature = "d57", feature = "wide")))]
impl<const SCALE: u32> ExpPolicy for D38<SCALE> {
#[inline]
fn exp_impl(self, mode: RoundingMode) -> Self {
Self(exp::fixed_d38::exp_strict::<SCALE>(self.0, mode))
}
#[inline]
fn exp_with_impl(self, working_digits: u32, mode: RoundingMode) -> Self {
Self(exp::fixed_d38::exp_with(self.0, SCALE, working_digits, mode))
}
#[inline]
fn exp2_impl(self, mode: RoundingMode) -> Self {
Self(exp::fixed_d38::exp2_strict::<SCALE>(self.0, mode))
}
#[inline]
fn exp2_with_impl(self, working_digits: u32, mode: RoundingMode) -> Self {
Self(exp::fixed_d38::exp2_with(self.0, SCALE, working_digits, mode))
}
}
macro_rules! impl_wide_exp {
($T:ident, $exp:path) => {
impl<const SCALE: u32> ExpPolicy for crate::types::widths::$T<SCALE> {
#[inline]
fn exp_impl(self, mode: RoundingMode) -> Self {
Self($exp(self.0, mode, SCALE))
}
#[inline]
fn exp_with_impl(self, _working_digits: u32, mode: RoundingMode) -> Self {
Self($exp(self.0, mode, SCALE))
}
#[inline]
fn exp2_impl(self, mode: RoundingMode) -> Self {
self.exp2_strict_with(mode)
}
#[inline]
fn exp2_with_impl(self, _working_digits: u32, mode: RoundingMode) -> Self {
self.exp2_strict_with(mode)
}
}
};
}
#[cfg(any(feature = "d57", feature = "wide"))]
impl<const SCALE: u32> ExpPolicy for crate::types::widths::D57<SCALE> {
#[inline]
fn exp_impl(self, mode: RoundingMode) -> Self {
if matches!(SCALE, 45..=56) {
return Self(exp::lookup_d57_s45_56::exp_strict::<SCALE>(self.0, mode));
}
Self(exp::wide_kernel::exp_strict_d57(self.0, mode, SCALE))
}
#[inline]
fn exp_with_impl(self, _working_digits: u32, mode: RoundingMode) -> Self {
if matches!(SCALE, 45..=56) {
return Self(exp::lookup_d57_s45_56::exp_strict::<SCALE>(self.0, mode));
}
Self(exp::wide_kernel::exp_strict_d57(self.0, mode, SCALE))
}
#[inline]
fn exp2_impl(self, mode: RoundingMode) -> Self {
self.exp2_strict_with(mode)
}
#[inline]
fn exp2_with_impl(self, _working_digits: u32, mode: RoundingMode) -> Self {
self.exp2_strict_with(mode)
}
}
#[cfg(any(feature = "d76", feature = "wide"))]
impl_wide_exp!(D76, exp::wide_kernel::exp_strict_d76);
#[cfg(any(feature = "d115", feature = "wide"))]
impl_wide_exp!(D115, exp::wide_kernel::exp_strict_d115);
#[cfg(any(feature = "d153", feature = "wide"))]
impl_wide_exp!(D153, exp::wide_kernel::exp_strict_d153);
#[cfg(any(feature = "d230", feature = "wide"))]
impl_wide_exp!(D230, exp::wide_kernel::exp_strict_d230);
#[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
impl_wide_exp!(D307, exp::wide_kernel::exp_strict_d307);
#[cfg(any(feature = "d462", feature = "x-wide"))]
impl_wide_exp!(D462, exp::wide_kernel::exp_strict_d462);
#[cfg(any(feature = "d616", feature = "x-wide"))]
impl_wide_exp!(D616, exp::wide_kernel::exp_strict_d616);
#[cfg(any(feature = "d924", feature = "xx-wide"))]
impl_wide_exp!(D924, exp::wide_kernel::exp_strict_d924);
#[cfg(any(feature = "d1232", feature = "xx-wide"))]
impl_wide_exp!(D1232, exp::wide_kernel::exp_strict_d1232);