use dashu_base::Approximation;
use dashu_base::Approximation::*;
use dashu_float::round::{Round, Rounding};
use dashu_float::{ConstCache, Context as FloatCtxt, FBig, FpError, Repr};
use dashu_int::Word;
use crate::cbig::CBig;
#[derive(Clone, Copy)]
pub struct Context<R: Round>(pub(crate) FloatCtxt<R>);
pub type CRounded<R, const B: Word> = Approximation<CBig<R, B>, (Rounding, Rounding)>;
pub type CfpResult<R, const B: Word> = Result<CRounded<R, B>, FpError>;
impl<R: Round> Context<R> {
#[inline]
pub const fn new(precision: usize) -> Self {
Self(FloatCtxt::new(precision))
}
#[inline]
pub const fn max(lhs: Self, rhs: Self) -> Self {
Self(FloatCtxt::max(lhs.0, rhs.0))
}
#[inline]
pub const fn precision(&self) -> usize {
self.0.precision()
}
#[inline]
pub(crate) const fn float(&self) -> FloatCtxt<R> {
self.0
}
#[inline]
pub(crate) fn guard(&self, g: usize) -> FloatCtxt<R> {
FloatCtxt::new(self.precision() + g)
}
#[inline]
pub fn unwrap_cfp<const B: Word>(&self, result: CfpResult<R, B>) -> CBig<R, B> {
match result {
Ok(rounded) => rounded.value(),
Err(FpError::Overflow(sign)) => CBig::overflow(self, sign),
Err(FpError::Underflow(sign)) => CBig::underflow(self, sign),
Err(FpError::InfiniteInput) => {
panic!("arithmetic operations with the infinity are not allowed!")
}
Err(FpError::OutOfDomain) => panic!("the operation result is out of domain!"),
Err(FpError::Indeterminate) => {
panic!("the result of the operation is an indeterminate form!")
}
}
}
}
pub(crate) fn combine_parts<R: Round, const B: Word>(
re: Approximation<FBig<R, B>, Rounding>,
im: Approximation<FBig<R, B>, Rounding>,
) -> CRounded<R, B> {
let (re_val, re_rnd) = match re {
Approximation::Exact(v) => (v, Rounding::NoOp),
Approximation::Inexact(v, r) => (v, r),
};
let (im_val, im_rnd) = match im {
Approximation::Exact(v) => (v, Rounding::NoOp),
Approximation::Inexact(v, r) => (v, r),
};
let value = CBig::from_parts(re_val, im_val);
if re_rnd == Rounding::NoOp && im_rnd == Rounding::NoOp {
Exact(value)
} else {
Inexact(value, (re_rnd, im_rnd))
}
}
pub(crate) fn exact<R: Round, const B: Word>(re: FBig<R, B>, im: FBig<R, B>) -> CRounded<R, B> {
Exact(CBig::from_parts(re, im))
}
pub(crate) fn riemann<R: Round, const B: Word>(context: Context<R>) -> CRounded<R, B> {
exact(
FBig::from_repr(Repr::infinity(), context.float()),
FBig::from_repr(Repr::zero(), context.float()),
)
}
#[inline]
#[allow(clippy::needless_option_as_deref)]
pub(crate) fn reborrow_cache<'a>(
cache: &'a mut Option<&mut ConstCache>,
) -> Option<&'a mut ConstCache> {
cache.as_deref_mut()
}
#[cfg(test)]
mod tests {
use super::*;
use dashu_base::Sign;
use dashu_float::round::mode;
use dashu_float::Repr;
#[test]
fn context_delegates_to_float() {
let ctx: Context<mode::HalfEven> = Context::new(53);
assert_eq!(ctx.precision(), 53);
let bigger = Context::max(ctx, Context::new(10));
assert_eq!(bigger.precision(), 53);
let limited_wins = Context::max(ctx, Context::new(0));
assert_eq!(limited_wins.precision(), 53);
let both_unlimited = Context::max(Context::<mode::HalfEven>::new(0), Context::new(0));
assert_eq!(both_unlimited.precision(), 0);
}
#[test]
fn combine_parts_exact_and_inexact() {
let ctx: Context<mode::HalfEven> = Context::new(10);
let f = ctx.float();
let one = FBig::from_repr(Repr::<2>::one(), f);
let combined = combine_parts(Exact(one.clone()), Exact(one.clone()));
assert!(matches!(combined, Exact(_)));
let add_one = f.add(one.repr(), one.repr()).unwrap(); let combined2 = combine_parts(add_one, Inexact(one, Rounding::AddOne));
assert!(matches!(combined2, Inexact(_, _)));
let _ = Sign::Positive; }
}