use super::Decimal;
use super::wide::{self, Wide};
use crate::ErrorKind;
use crate::number::MAX_FACTORIAL;
fn domain(valid: bool) -> Result<(), ErrorKind> {
if valid {
Ok(())
} else {
Err(ErrorKind::Domain)
}
}
impl<const DIGITS: u32, const MAX_EXPONENT: i32> Decimal<DIGITS, MAX_EXPONENT> {
fn wide(self) -> Wide {
Wide::new(
self.negative,
u128::from(self.coefficient),
i64::from(self.exponent),
)
}
fn from_wide(value: Wide) -> Result<Self, ErrorKind> {
let (negative, coefficient, exponent) = value.parts();
Self::from_parts(negative, (coefficient + 5000) / 10_000, exponent + 4, false)
}
fn is_odd(self) -> bool {
let integer = match self.exponent {
0 => u128::from(self.coefficient),
exponent if exponent > 0 => 0,
exponent => 10_u128
.checked_pow(exponent.unsigned_abs())
.map_or(0, |divisor| u128::from(self.coefficient) / divisor),
};
self.is_integer() && integer % 2 == 1
}
pub(super) fn fact(self) -> Result<Self, ErrorKind> {
domain(self.is_integer() && (!self.negative || self.is_zero()))?;
let last = self
.to_integer()
.filter(|last| last.unsigned_abs() <= MAX_FACTORIAL as u64)
.ok_or(ErrorKind::Overflow)?;
let mut product = Wide::ONE;
for factor in 2..=last {
product = product.mul(Wide::integer(factor));
if product.parts().2 > i64::from(MAX_EXPONENT) {
return Err(ErrorKind::Overflow);
}
}
Self::from_wide(product)
}
pub(super) fn pow(self, exponent: Self) -> Result<Self, ErrorKind> {
if self.is_zero() {
return if exponent.negative {
Err(ErrorKind::DivisionByZero)
} else if exponent.is_zero() {
Ok(Self::one())
} else {
Ok(Self::ZERO)
};
}
if let Some(integer) = exponent
.to_integer()
.filter(|integer| integer.unsigned_abs() <= 1024)
{
let mut result = Wide::ONE;
let mut base = self.wide();
let mut remaining = integer.unsigned_abs();
while remaining != 0 {
if remaining & 1 == 1 {
result = result.mul(base);
}
base = base.mul(base);
remaining >>= 1;
}
return Self::from_wide(if integer < 0 {
Wide::ONE.div(result)
} else {
result
});
}
domain(!self.negative || exponent.is_integer())?;
let magnitude = wide::exp(exponent.wide().mul(wide::ln(self.wide().abs())));
Self::from_wide(magnitude.signed(self.negative && exponent.is_odd()))
}
pub(crate) fn sqrt(self) -> Result<Self, ErrorKind> {
domain(!self.negative)?;
Self::from_wide(self.wide().sqrt())
}
pub(crate) fn cbrt(self) -> Result<Self, ErrorKind> {
if self.is_zero() {
return Ok(self);
}
let root = wide::exp(wide::ln(self.wide().abs()).div(Wide::integer(3)));
Self::from_wide(root.signed(self.negative))
}
pub(crate) fn exp(self) -> Result<Self, ErrorKind> {
Self::from_wide(wide::exp(self.wide()))
}
fn wide_ln(self) -> Result<Wide, ErrorKind> {
domain(!self.negative && !self.is_zero())?;
Ok(wide::ln(self.wide()))
}
pub(crate) fn ln(self) -> Result<Self, ErrorKind> {
Self::from_wide(self.wide_ln()?)
}
pub(crate) fn log2(self) -> Result<Self, ErrorKind> {
Self::from_wide(self.wide_ln()?.div(Wide::LN_2))
}
pub(crate) fn log10(self) -> Result<Self, ErrorKind> {
domain(!self.negative && !self.is_zero())?;
let (power, rest) = wide::ln_parts(self.wide());
Self::from_wide(Wide::integer(power).add(rest.div(Wide::LN_10)))
}
pub(crate) fn log(self, base: Self) -> Result<Self, ErrorKind> {
domain(base != Self::one())?;
Self::from_wide(self.wide_ln()?.div(base.wide_ln()?))
}
fn sine_cosine(self) -> Result<(Wide, Wide), ErrorKind> {
let (sine, cosine) =
wide::sine_cosine(self.coefficient, self.exponent).ok_or(ErrorKind::Domain)?;
Ok((sine.signed(self.negative), cosine))
}
pub(crate) fn sin(self) -> Result<Self, ErrorKind> {
Self::from_wide(self.sine_cosine()?.0)
}
pub(crate) fn cos(self) -> Result<Self, ErrorKind> {
Self::from_wide(self.sine_cosine()?.1)
}
pub(crate) fn tan(self) -> Result<Self, ErrorKind> {
let (sine, cosine) = self.sine_cosine()?;
Self::from_wide(sine.div(cosine))
}
fn complement(self) -> Result<Wide, ErrorKind> {
domain(self.abs() <= Self::one())?;
let x = self.wide();
Ok(Wide::ONE.sub(x).mul(Wide::ONE.add(x)).sqrt())
}
pub(crate) fn asin(self) -> Result<Self, ErrorKind> {
Self::from_wide(wide::atan2(self.wide(), self.complement()?))
}
pub(crate) fn acos(self) -> Result<Self, ErrorKind> {
Self::from_wide(wide::atan2(self.complement()?, self.wide()))
}
pub(crate) fn atan(self) -> Result<Self, ErrorKind> {
Self::from_wide(wide::atan(self.wide()))
}
pub(crate) fn atan2(self, x: Self) -> Result<Self, ErrorKind> {
Self::from_wide(wide::atan2(self.wide(), x.wide()))
}
pub(crate) fn sinh(self) -> Result<Self, ErrorKind> {
Self::from_wide(wide::sinh(self.wide()))
}
pub(crate) fn cosh(self) -> Result<Self, ErrorKind> {
Self::from_wide(wide::cosh(self.wide()))
}
pub(crate) fn tanh(self) -> Result<Self, ErrorKind> {
Self::from_wide(wide::tanh(self.wide()))
}
pub(crate) fn asinh(self) -> Result<Self, ErrorKind> {
let x = self.wide().abs();
let square = x.mul(x);
let u = x.add(square.div(Wide::ONE.add(Wide::ONE.add(square).sqrt())));
Self::from_wide(wide::ln_1p(u).signed(self.negative))
}
pub(crate) fn acosh(self) -> Result<Self, ErrorKind> {
domain(self >= Self::one())?;
let u = self.wide().sub(Wide::ONE);
Self::from_wide(wide::ln_1p(u.add(u.mul(u.add(Wide::TWO)).sqrt())))
}
pub(crate) fn atanh(self) -> Result<Self, ErrorKind> {
domain(self.abs() < Self::one())?;
let x = self.wide().abs();
let logarithm = wide::ln_1p(x.add(x).div(Wide::ONE.sub(x)));
Self::from_wide(logarithm.mul(Wide::HALF).signed(self.negative))
}
pub(crate) fn hypot(self, y: Self) -> Result<Self, ErrorKind> {
let (x, y) = (self.wide(), y.wide());
Self::from_wide(x.mul(x).add(y.mul(y)).sqrt())
}
}