use crate::fixed_point::fixed_num::{Compute, FixedNum};
#[inline]
pub fn one<T: FixedNum>() -> Compute<T> {
T::make_compute_int(1)
}
#[inline]
pub fn ceiling<T: FixedNum>() -> Compute<T> {
T::compute_ceiling()
}
#[inline]
pub fn from_fixed<T: FixedNum>(x: T) -> Compute<T> {
T::upscale_to_compute(x.raw_storage())
}
#[inline]
pub fn to_fixed<T: FixedNum>(x: Compute<T>) -> T {
try_to_fixed(x).expect("compute_tier::to_fixed: value does not fit the storage tier")
}
#[inline]
pub fn try_to_fixed<T: FixedNum>(x: Compute<T>) -> Option<T> {
Some(T::from_raw_storage(T::downscale_to_storage(x).ok()?))
}
#[inline]
pub fn exp<T: FixedNum>(x: Compute<T>) -> Compute<T> {
T::exp_at_compute_tier(x)
}
#[inline]
pub fn ln<T: FixedNum>(x: Compute<T>) -> Compute<T> {
assert!(
!(T::compute_is_negative(&x) || T::compute_is_zero(&x)),
"compute_tier::ln: x <= 0 is outside the domain"
);
T::ln_at_compute_tier(x)
}
#[inline]
pub fn sqrt<T: FixedNum>(x: Compute<T>) -> Compute<T> {
assert!(
!T::compute_is_negative(&x),
"compute_tier::sqrt: x < 0 is outside the domain"
);
T::sqrt_at_compute_tier(x)
}
#[inline]
pub fn sinhcosh<T: FixedNum>(x: Compute<T>) -> (Compute<T>, Compute<T>) {
T::sinhcosh_at_compute_tier(x)
}
#[inline]
pub fn sigmoid<T: FixedNum>(x: Compute<T>) -> Compute<T> {
let one = T::make_compute_int(1);
if T::compute_is_negative(&x) {
let e = T::exp_at_compute_tier(x);
T::compute_divide(e, T::compute_add(one, e))
.expect("sigmoid: denominator in [1,2] cannot overflow")
} else {
let e = T::exp_at_compute_tier(T::compute_negate(x));
T::compute_divide(one, T::compute_add(one, e))
.expect("sigmoid: denominator in [1,2] cannot overflow")
}
}
#[inline]
pub fn softplus<T: FixedNum>(x: Compute<T>) -> Compute<T> {
let one = T::make_compute_int(1);
let neg_abs = if T::compute_is_negative(&x) { x } else { T::compute_negate(x) };
let e = T::exp_at_compute_tier(neg_abs); let corr = T::ln_at_compute_tier(T::compute_add(one, e)); if T::compute_is_negative(&x) {
corr
} else {
T::compute_checked_add(x, corr)
.expect("softplus: result does not fit the compute tier")
}
}
#[inline]
pub fn ln1p<T: FixedNum>(x: Compute<T>) -> Compute<T> {
let arg = T::compute_checked_add(T::make_compute_int(1), x)
.expect("ln1p: 1 + x does not fit the compute tier");
assert!(
!(T::compute_is_negative(&arg) || T::compute_is_zero(&arg)),
"compute_tier::ln1p: x <= -1 is outside the domain"
);
T::ln_at_compute_tier(arg)
}