ebi_arithmetic 0.3.13

Exact arithmetic for Ebi - a stochastic process mining utility
Documentation
use std::cmp::Ordering;

use crate::{
    ebi_number::{Signed, Zero},
    fraction::{
        fraction::EPSILON, fraction_enum::FractionEnum, fraction_exact::FractionExact,
        fraction_f64::FractionF64,
    },
};
use malachite::{
    Integer, Natural,
    base::num::{
        arithmetic::traits::{Abs, Sign},
        basic::traits::Zero as MZero,
    },
    rational::Rational,
};

impl Signed for FractionF64 {
    fn abs(self) -> Self {
        Self(self.0.abs())
    }

    fn is_positive(&self) -> bool {
        self.0 != 0f64 && self.0 > EPSILON
    }

    fn is_negative(&self) -> bool {
        self.0 != 0f64 && self.0 < -EPSILON
    }

    fn is_not_negative(&self) -> bool {
        self.0.is_not_negative()
    }

    fn is_not_positive(&self) -> bool {
        self.0.is_not_positive()
    }
}

impl Signed for FractionExact {
    fn abs(self) -> Self {
        Self(Signed::abs(self.0))
    }

    fn is_positive(&self) -> bool {
        self.0.is_positive()
    }

    fn is_negative(&self) -> bool {
        self.0.is_negative()
    }

    fn is_not_negative(&self) -> bool {
        !self.is_negative()
    }

    fn is_not_positive(&self) -> bool {
        !self.is_positive()
    }
}

impl Signed for FractionEnum {
    fn abs(self) -> Self {
        match self {
            FractionEnum::Exact(f) => FractionEnum::Exact(Abs::abs(f)),
            FractionEnum::Approx(f) => FractionEnum::Approx(f.abs()),
            FractionEnum::CannotCombineExactAndApprox => self.clone(),
        }
    }

    fn is_positive(&self) -> bool {
        match self {
            FractionEnum::Exact(f) => Signed::is_positive(f),
            FractionEnum::Approx(f) => Signed::is_positive(f),
            FractionEnum::CannotCombineExactAndApprox => false,
        }
    }

    fn is_negative(&self) -> bool {
        match self {
            FractionEnum::Exact(f) => Signed::is_negative(f),
            FractionEnum::Approx(f) => Signed::is_negative(f),
            FractionEnum::CannotCombineExactAndApprox => false,
        }
    }

    fn is_not_negative(&self) -> bool {
        match self {
            FractionEnum::Exact(_) => !self.is_negative(),
            FractionEnum::Approx(f) => f.is_not_negative(),
            FractionEnum::CannotCombineExactAndApprox => false,
        }
    }

    fn is_not_positive(&self) -> bool {
        match self {
            FractionEnum::Exact(_) => !self.is_positive(),
            FractionEnum::Approx(f) => f.is_not_positive(),
            FractionEnum::CannotCombineExactAndApprox => false,
        }
    }
}

impl Signed for Rational {
    fn abs(self) -> Self {
        Abs::abs(self)
    }

    fn is_positive(&self) -> bool {
        self > &Rational::ZERO
    }

    fn is_negative(&self) -> bool {
        self < &Rational::ZERO
    }
}

impl Signed for Integer {
    fn abs(self) -> Self {
        Abs::abs(self)
    }

    fn is_positive(&self) -> bool {
        self > &Integer::ZERO
    }

    fn is_negative(&self) -> bool {
        self < &Integer::ZERO
    }
}

impl Signed for Natural {
    fn abs(self) -> Self {
        self
    }

    fn is_positive(&self) -> bool {
        self > &Natural::ZERO
    }

    fn is_negative(&self) -> bool {
        false
    }
}

macro_rules! float {
    ($t: ident, $e: expr) => {
        impl Signed for $t {
            fn abs(self) -> Self {
                $t::abs(self)
            }

            fn is_positive(&self) -> bool {
                *self != 0.0 && self > &$e
            }

            fn is_negative(&self) -> bool {
                *self != 0.0 && self < &-$e
            }

            fn is_not_negative(&self) -> bool {
                self > &-$e
            }

            fn is_not_positive(&self) -> bool {
                self < &$e
            }
        }
    };
}

float!(f32, f32::EPSILON);
float!(f64, EPSILON);

macro_rules! ttype {
    ($t:ident) => {
        impl Signed for $t {
            fn abs(self) -> Self {
                self
            }

            fn is_positive(&self) -> bool {
                *self > 0
            }

            fn is_negative(&self) -> bool {
                false
            }
        }
    };
}

macro_rules! ttype_signed {
    ($t:ident) => {
        impl Signed for $t {
            fn abs(self) -> Self {
                $t::abs(self)
            }

            fn is_positive(&self) -> bool {
                self > &$t::zero()
            }

            fn is_negative(&self) -> bool {
                self < &$t::zero()
            }
        }
    };
}

ttype!(usize);
ttype!(u128);
ttype!(u64);
ttype!(u32);
ttype!(u16);
ttype!(u8);
ttype_signed!(i128);
ttype_signed!(i64);
ttype_signed!(i32);
ttype_signed!(i16);
ttype_signed!(i8);

pub trait Numerator {
    fn signed_numerator(&self) -> Integer;
}

impl Numerator for Rational {
    fn signed_numerator(&self) -> Integer {
        if self.sign() == Ordering::Less {
            -self.numerator_ref()
        } else {
            self.to_numerator().into()
        }
    }
}