use crate::{generic::GenericInteger, BigFraction, GenericFraction};
use num::{rational::Ratio, traits::Pow, BigUint, Integer};
pub mod sqrt;
#[derive(Clone, Debug)]
pub enum Accuracy {
#[cfg(feature = "lazy_static")]
Dp20,
#[cfg(feature = "lazy_static")]
Dp100,
#[cfg(feature = "lazy_static")]
Dp500,
Custom {
multiplier: BigUint,
},
}
impl Accuracy {
#[must_use]
pub fn decimal_places<N: GenericInteger>(n: N) -> Self
where
BigUint: Pow<N>,
<BigUint as Pow<N>>::Output: Into<BigUint>,
{
#[cfg(feature = "lazy_static")]
{
match n.to_u16() {
Some(20) => return Self::Dp20,
Some(100) => return Self::Dp100,
Some(500) => return Self::Dp500,
_ => (),
}
}
Self::Custom {
multiplier: Pow::pow(BigUint::from(10_u8), n).into(),
}
}
pub fn base_places<B: GenericInteger, N: GenericInteger>(base: B, n: N) -> Self
where
B: Into<BigUint>,
BigUint: Pow<N>,
<BigUint as Pow<N>>::Output: Into<BigUint>,
{
Self::Custom {
multiplier: Pow::pow(base.into(), n).into(),
}
}
pub fn chop<T>(&self, fraction: &GenericFraction<T>) -> BigFraction
where
T: Clone + Integer,
BigUint: From<T>,
{
match fraction {
GenericFraction::Rational(sign, ratio) => BigFraction::Rational(*sign, {
self.chop_ratio(&Ratio::new_raw(
ratio.numer().clone().into(),
ratio.denom().clone().into(),
))
}),
GenericFraction::Infinity(sign) => BigFraction::Infinity(*sign),
GenericFraction::NaN => BigFraction::NaN,
}
}
#[must_use]
fn chop_ratio(&self, ratio: &Ratio<BigUint>) -> Ratio<BigUint> {
Ratio::new(
self.chopped_numerator_raw(ratio.numer(), ratio.denom()),
self.multiplier().clone(),
)
}
fn chopped_numerator_raw(&self, numer: &BigUint, denom: &BigUint) -> BigUint {
(numer * self.multiplier()) / denom
}
#[must_use]
pub fn multiplier(&self) -> &BigUint {
#[cfg(feature = "lazy_static")]
{
lazy_static! {
static ref DP20_MUL: BigUint = BigUint::from(10_u8).pow(20_u32);
static ref DP100_MUL: BigUint = BigUint::from(10_u8).pow(100_u32);
static ref DP500_MUL: BigUint = BigUint::from(10_u8).pow(500_u32);
};
return match self {
Accuracy::Dp20 => &DP20_MUL,
Accuracy::Dp100 => &DP100_MUL,
Accuracy::Dp500 => &DP500_MUL,
Accuracy::Custom { multiplier } => multiplier,
};
}
#[allow(unreachable_code)]
{
let Accuracy::Custom { multiplier } = self else {
unreachable!()
};
multiplier
}
}
}
impl Default for Accuracy {
fn default() -> Self {
Self::Dp100
}
}