Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  arithmetic_impls.rs   Sprache: unbekannt

 
// #[rustfmt::skip] is being used because `rustfmt` poorly formats `#[doc = concat!(..)]`. See
// https://github.com/rust-lang/rustfmt/issues/5062 for more information.

use crate::{decimal::CalculationResult, ops, Decimal};
use core::ops::{Add, Div, Mul, Rem, Sub};
use num_traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedRem, CheckedSub, Inv};

// Macros and `Decimal` implementations

#[rustfmt::skip]
macro_rules! impl_checked {
    ($long:literal, $short:literal, $fun:ident, $impl:ident) => {
        #[doc = concat!(
            "Checked ",
            $long,
            ". Computes `self ",
            $short,
            " other`, returning `None` if overflow occurred."
        )]
        #[inline(always)]
        #[must_use]
        pub fn $fun(self, other: Decimal) -> Option<Decimal> {
            match ops::$impl(&self, &other) {
                CalculationResult::Ok(result) => Some(result),
                _ => None,
            }
        }
    };
}

#[rustfmt::skip]
macro_rules! impl_saturating {
    ($long:literal, $short:literal, $fun:ident, $impl:ident, $cmp:ident) => {
        #[doc = concat!(
            "Saturating ",
            $long,
            ". Computes `self ",
            $short,
            " other`, saturating at the relevant upper or lower boundary.",
        )]
        #[inline(always)]
        #[must_use]
        pub fn $fun(self, other: Decimal) -> Decimal {
            if let Some(elem) = self.$impl(other) {
                elem
            } else {
                $cmp(&self, &other)
            }
        }
    };
}

macro_rules! impl_checked_and_saturating {
    (
        $op_long:literal,
        $op_short:literal,
        $checked_fun:ident,
        $checked_impl:ident,

        $saturating_fun:ident,
        $saturating_cmp:ident
    ) => {
        impl_checked!($op_long, $op_short, $checked_fun, $checked_impl);
        impl_saturating!(
            $op_long,
            $op_short,
            $saturating_fun,
            $checked_fun,
            $saturating_cmp
        );
    };
}

impl Decimal {
    impl_checked_and_saturating!(
        "addition",
        "+",
        checked_add,
        add_impl,
        saturating_add,
        if_a_is_positive_then_max
    );
    impl_checked_and_saturating!(
        "multiplication",
        "*",
        checked_mul,
        mul_impl,
        saturating_mul,
        if_xnor_then_max
    );
    impl_checked_and_saturating!(
        "subtraction",
        "-",
        checked_sub,
        sub_impl,
        saturating_sub,
        if_a_is_positive_then_max
    );

    impl_checked!("division", "/", checked_div, div_impl);
    impl_checked!("remainder", "%", checked_rem, rem_impl);
}

// Macros and trait implementations

macro_rules! forward_all_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        forward_val_val_binop!(impl $imp for $res, $method);
        forward_ref_val_binop!(impl $imp for $res, $method);
        forward_val_ref_binop!(impl $imp for $res, $method);
    };
}

macro_rules! forward_ref_val_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a> $imp<$res> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                self.$method(&other)
            }
        }
    };
}

macro_rules! forward_val_ref_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a> $imp<&'a $res> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                (&self).$method(other)
            }
        }
    };
}

macro_rules! forward_val_val_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl $imp<$res> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                (&self).$method(&other)
            }
        }
    };
}

forward_all_binop!(impl Add for Decimal, add);
impl<'a, 'b> Add<&'b Decimal> for &'a Decimal {
    type Output = Decimal;

    #[inline(always)]
    fn add(self, other: &Decimal) -> Decimal {
        match ops::add_impl(self, other) {
            CalculationResult::Ok(sum) => sum,
            _ => panic!("Addition overflowed"),
        }
    }
}

impl CheckedAdd for Decimal {
    #[inline]
    fn checked_add(&self, v: &Decimal) -> Option<Decimal> {
        Decimal::checked_add(*self, *v)
    }
}

impl CheckedSub for Decimal {
    #[inline]
    fn checked_sub(&self, v: &Decimal) -> Option<Decimal> {
        Decimal::checked_sub(*self, *v)
    }
}

impl CheckedMul for Decimal {
    #[inline]
    fn checked_mul(&self, v: &Decimal) -> Option<Decimal> {
        Decimal::checked_mul(*self, *v)
    }
}

impl CheckedDiv for Decimal {
    #[inline]
    fn checked_div(&self, v: &Decimal) -> Option<Decimal> {
        Decimal::checked_div(*self, *v)
    }
}

impl CheckedRem for Decimal {
    #[inline]
    fn checked_rem(&self, v: &Decimal) -> Option<Decimal> {
        Decimal::checked_rem(*self, *v)
    }
}

impl Inv for Decimal {
    type Output = Self;

    #[inline]
    fn inv(self) -> Self {
        Decimal::ONE / self
    }
}

forward_all_binop!(impl Div for Decimal, div);
impl<'a, 'b> Div<&'b Decimal> for &'a Decimal {
    type Output = Decimal;

    #[inline]
    fn div(self, other: &Decimal) -> Decimal {
        match ops::div_impl(self, other) {
            CalculationResult::Ok(quot) => quot,
            CalculationResult::Overflow => panic!("Division overflowed"),
            CalculationResult::DivByZero => panic!("Division by zero"),
        }
    }
}

forward_all_binop!(impl Mul for Decimal, mul);
impl<'a, 'b> Mul<&'b Decimal> for &'a Decimal {
    type Output = Decimal;

    #[inline]
    fn mul(self, other: &Decimal) -> Decimal {
        match ops::mul_impl(self, other) {
            CalculationResult::Ok(prod) => prod,
            _ => panic!("Multiplication overflowed"),
        }
    }
}

forward_all_binop!(impl Rem for Decimal, rem);
impl<'a, 'b> Rem<&'b Decimal> for &'a Decimal {
    type Output = Decimal;

    #[inline]
    fn rem(self, other: &Decimal) -> Decimal {
        match ops::rem_impl(self, other) {
            CalculationResult::Ok(rem) => rem,
            CalculationResult::Overflow => panic!("Division overflowed"),
            CalculationResult::DivByZero => panic!("Division by zero"),
        }
    }
}

forward_all_binop!(impl Sub for Decimal, sub);
impl<'a, 'b> Sub<&'b Decimal> for &'a Decimal {
    type Output = Decimal;

    #[inline(always)]
    fn sub(self, other: &Decimal) -> Decimal {
        match ops::sub_impl(self, other) {
            CalculationResult::Ok(sum) => sum,
            _ => panic!("Subtraction overflowed"),
        }
    }
}

// This function signature is expected by `impl_saturating`, thus the reason of `_b`.
#[inline(always)]
const fn if_a_is_positive_then_max(a: &Decimal, _b: &Decimal) -> Decimal {
    if a.is_sign_positive() {
        Decimal::MAX
    } else {
        Decimal::MIN
    }
}

// Used by saturating multiplications.
//
// If the `a` and `b` combination represents a XNOR bit operation, returns MAX. Otherwise,
// returns MIN.
#[inline(always)]
const fn if_xnor_then_max(a: &Decimal, b: &Decimal) -> Decimal {
    match (a.is_sign_positive(), b.is_sign_positive()) {
        (true, true) => Decimal::MAX,
        (true, false) => Decimal::MIN,
        (false, true) => Decimal::MIN,
        (false, false) => Decimal::MAX,
    }
}

#[cfg(test)]
mod tests {
    use crate::Decimal;

    #[test]
    fn checked_methods_have_correct_output() {
        assert_eq!(Decimal::MAX.checked_add(Decimal::MAX), None);
        assert_eq!(Decimal::MAX.checked_add(Decimal::MIN), Some(Decimal::ZERO));
        assert_eq!(Decimal::MAX.checked_div(Decimal::ZERO), None);
        assert_eq!(Decimal::MAX.checked_mul(Decimal::MAX), None);
        assert_eq!(Decimal::MAX.checked_mul(Decimal::MIN), None);
        assert_eq!(Decimal::MAX.checked_rem(Decimal::ZERO), None);
        assert_eq!(Decimal::MAX.checked_sub(Decimal::MAX), Some(Decimal::ZERO));
        assert_eq!(Decimal::MAX.checked_sub(Decimal::MIN), None);

        assert_eq!(Decimal::MIN.checked_add(Decimal::MAX), Some(Decimal::ZERO));
        assert_eq!(Decimal::MIN.checked_add(Decimal::MIN), None);
        assert_eq!(Decimal::MIN.checked_div(Decimal::ZERO), None);
        assert_eq!(Decimal::MIN.checked_mul(Decimal::MAX), None);
        assert_eq!(Decimal::MIN.checked_mul(Decimal::MIN), None);
        assert_eq!(Decimal::MIN.checked_rem(Decimal::ZERO), None);
        assert_eq!(Decimal::MIN.checked_sub(Decimal::MAX), None);
        assert_eq!(Decimal::MIN.checked_sub(Decimal::MIN), Some(Decimal::ZERO));
    }

    #[test]
    fn saturated_methods_have_correct_output() {
        assert_eq!(Decimal::MAX.saturating_add(Decimal::MAX), Decimal::MAX);
        assert_eq!(Decimal::MAX.saturating_add(Decimal::MIN), Decimal::ZERO);
        assert_eq!(Decimal::MAX.saturating_mul(Decimal::MAX), Decimal::MAX);
        assert_eq!(Decimal::MAX.saturating_mul(Decimal::MIN), Decimal::MIN);
        assert_eq!(Decimal::MAX.saturating_sub(Decimal::MAX), Decimal::ZERO);
        assert_eq!(Decimal::MAX.saturating_sub(Decimal::MIN), Decimal::MAX);

        assert_eq!(Decimal::MIN.saturating_add(Decimal::MAX), Decimal::ZERO);
        assert_eq!(Decimal::MIN.saturating_add(Decimal::MIN), Decimal::MIN);
        assert_eq!(Decimal::MIN.saturating_mul(Decimal::MAX), Decimal::MIN);
        assert_eq!(Decimal::MIN.saturating_mul(Decimal::MIN), Decimal::MAX);
        assert_eq!(Decimal::MIN.saturating_sub(Decimal::MAX), Decimal::MIN);
        assert_eq!(Decimal::MIN.saturating_sub(Decimal::MIN), Decimal::ZERO);
    }
}

[ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge