use dashu_base::Sign;
use dashu_int::Word;
use crate::fbig::FBig;
use crate::repr::{Context, Repr};
use crate::round::{Round, Rounded};
use core::fmt::{self, Display, Formatter};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FpError {
InfiniteInput,
OutOfDomain,
Indeterminate,
Overflow(Sign),
Underflow(Sign),
}
impl Display for FpError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
FpError::InfiniteInput => {
f.write_str("arithmetic with an infinite input is not allowed")
}
FpError::OutOfDomain => f.write_str("the operation result is out of domain"),
FpError::Indeterminate => f.write_str("the operation result is an indeterminate form"),
FpError::Overflow(_) => f.write_str("overflow: the result is too large to represent"),
FpError::Underflow(_) => f.write_str("underflow: the result is too small to represent"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for FpError {}
pub type FpResult<T> = Result<Rounded<T>, FpError>;
#[inline]
pub const fn assert_finite<const B: Word>(repr: &Repr<B>) {
if repr.is_infinite() {
panic_operate_with_inf()
}
}
#[inline]
pub const fn assert_finite_operands<const B: Word>(lhs: &Repr<B>, rhs: &Repr<B>) {
if lhs.is_infinite() || rhs.is_infinite() {
panic_operate_with_inf()
}
}
pub const fn panic_operate_with_inf() -> ! {
panic!("arithmetic operations with the infinity are not allowed!")
}
pub const fn assert_limited_precision(precision: usize) {
if precision == 0 {
panic_unlimited_precision()
}
}
pub const fn panic_unlimited_precision() -> ! {
panic!("precision cannot be 0 (unlimited) for this operation!")
}
pub fn panic_root_zeroth() -> ! {
panic!("finding 0th root is not allowed!")
}
pub fn panic_nan() -> ! {
panic!("the result of the operation is NaN!")
}
pub fn panic_out_of_domain() -> ! {
panic!("the operation result is out of domain!")
}
impl<R: Round> Context<R> {
#[inline]
pub fn unwrap_fp<const B: Word>(&self, result: FpResult<FBig<R, B>>) -> FBig<R, B> {
match result {
Ok(value) => value.value(),
Err(FpError::Overflow(sign)) => FBig::new(Repr::infinity_with_sign(sign), *self),
Err(FpError::Underflow(sign)) => FBig::new(Repr::zero_with_sign(sign), *self),
Err(FpError::InfiniteInput) => panic_operate_with_inf(),
Err(FpError::OutOfDomain) => panic_out_of_domain(),
Err(FpError::Indeterminate) => panic_nan(),
}
}
#[inline]
pub(crate) fn unwrap_fp_repr<const B: Word>(&self, result: FpResult<Repr<B>>) -> Repr<B> {
match result {
Ok(value) => value.value(),
Err(FpError::Overflow(sign)) => Repr::infinity_with_sign(sign),
Err(FpError::Underflow(sign)) => Repr::zero_with_sign(sign),
Err(FpError::InfiniteInput) => panic_operate_with_inf(),
Err(FpError::OutOfDomain) => panic_out_of_domain(),
Err(FpError::Indeterminate) => panic_nan(),
}
}
}