primitive_fixed_point_decimal 0.3.0

Primitive fixed-point decimal types.
Documentation
use crate::fpdec_inner::FpdecInner;
use int_div_cum_error::{
    Rounding,
    checked_divide_with_rounding,
    checked_divide_with_cum_error,
};

macro_rules! calc_mul_div_higher {
    (
        $a:expr, $b:expr, $c:expr,
        $rounding:expr, $cum_error:expr,
        $origin_type:ty, $higher_type:ty
    ) => {
        {
            match $cum_error {
                Some(cum_error) => {
                    let mut higher_cum_error = *cum_error as $higher_type;
                    let q = checked_divide_with_cum_error(
                        $a as $higher_type * $b as $higher_type,
                        $c as $higher_type,
                        $rounding,
                        &mut higher_cum_error)?;

                    *cum_error = higher_cum_error as $origin_type;
                    <$origin_type>::try_from(q).ok()
                }
                None => {
                    let q = checked_divide_with_rounding(
                        $a as $higher_type * $b as $higher_type,
                        $c as $higher_type,
                        $rounding)?;
                    <$origin_type>::try_from(q).ok()
                }
            }
        }
    }
}

impl FpdecInner for i8 {
    const MAX: Self = i8::MAX;
    const MIN: Self = i8::MIN;
    const MAX_POWERS: Self = 10_i8.pow(2);

    fn get_exp(i: usize) -> Option<Self> {
        const ALL_EXPS: [i8; 3] = [
            1, 10_i8.pow(1), 10_i8.pow(2)
        ];

        ALL_EXPS.get(i).copied()
    }

    fn calc_mul_div(self, b: Self, c: Self, rounding: Rounding, cum_error: Option<&mut Self>)
        -> Option<Self>
    {
        calc_mul_div_higher!(self, b, c, rounding, cum_error, i8, i16)
    }
}

impl FpdecInner for i16 {
    const MAX: Self = i16::MAX;
    const MIN: Self = i16::MIN;
    const MAX_POWERS: Self = 10_i16.pow(4);

    fn get_exp(i: usize) -> Option<Self> {
        const ALL_EXPS: [i16; 5] = [
            1,
            10_i16.pow(1), 10_i16.pow(2), 10_i16.pow(3), 10_i16.pow(4),
        ];

        ALL_EXPS.get(i).copied()
    }

    fn calc_mul_div(self, b: Self, c: Self, rounding: Rounding, cum_error: Option<&mut Self>)
        -> Option<Self>
    {
        calc_mul_div_higher!(self, b, c, rounding, cum_error, i16, i32)
    }
}

impl FpdecInner for i32 {
    const MAX: Self = i32::MAX;
    const MIN: Self = i32::MIN;
    const MAX_POWERS: Self = 10_i32.pow(9);

    fn get_exp(i: usize) -> Option<Self> {
        const ALL_EXPS: [i32; 10] = [
            1,
            10_i32.pow(1), 10_i32.pow(2), 10_i32.pow(3), 10_i32.pow(4),
            10_i32.pow(5), 10_i32.pow(6), 10_i32.pow(7), 10_i32.pow(8),
            10_i32.pow(9)
        ];

        ALL_EXPS.get(i).copied()
    }

    fn calc_mul_div(self, b: Self, c: Self, rounding: Rounding, cum_error: Option<&mut Self>)
        -> Option<Self>
    {
        calc_mul_div_higher!(self, b, c, rounding, cum_error, i32, i64)
    }
}

impl FpdecInner for i64 {
    const MAX: Self = i64::MAX;
    const MIN: Self = i64::MIN;
    const MAX_POWERS: Self = 10_i64.pow(18);

    fn get_exp(i: usize) -> Option<Self> {
        const ALL_EXPS: [i64; 19] = [
            1,
            10_i64.pow(1), 10_i64.pow(2), 10_i64.pow(3), 10_i64.pow(4),
            10_i64.pow(5), 10_i64.pow(6), 10_i64.pow(7), 10_i64.pow(8),
            10_i64.pow(9), 10_i64.pow(10), 10_i64.pow(11), 10_i64.pow(12),
            10_i64.pow(13), 10_i64.pow(14), 10_i64.pow(15), 10_i64.pow(16),
            10_i64.pow(17), 10_i64.pow(18),
        ];

        ALL_EXPS.get(i).copied()
    }

    fn calc_mul_div(self, b: Self, c: Self, rounding: Rounding, cum_error: Option<&mut Self>)
    -> Option<Self>
    {
        calc_mul_div_higher!(self, b, c, rounding, cum_error, i64, i128)
    }
}