1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// ---------------------------------------------------------------------------
// Copyright:   (c) 2021 ff. Michael Amrhein (michael@adrhinum.de)
// License:     This program is part of a larger application. For license
//              details please read the file LICENSE.TXT provided together
//              with the application.
// ---------------------------------------------------------------------------
// $Source: src/quantize.rs $
// $Revision: 2022-01-02T11:24:00+01:00 $

use core::ops::Mul;

use crate::DivRounded;

/// Rounding a number to the nearest integer multiple of a given quantum.
pub trait Quantize<Rhs = Self> {
    /// The resulting type after applying `quantize`.
    type Output;

    /// Returns an instance of `Self::Output` with its value set to the integer
    /// multiple of `quant` nearest to `self`, according to the current
    /// [RoundingMode](crate::RoundingMode).
    ///
    /// # Panics
    ///
    /// Panics if `quant` equals zero or the resulting value can not be
    /// represented by `Self::Output`!
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use fpdec::{Dec, Decimal, Quantize};
    /// let i = -322_i32;
    /// let q = 3_i32;
    /// let r = i.quantize(q);
    /// assert_eq!(r.to_string(), "-321");
    /// let d = Dec!(28.27093);
    /// let q = 5_u32;
    /// let r = d.quantize(q);
    /// assert_eq!(r.to_string(), "30");
    /// let q = Dec!(0.05);
    /// let r = d.quantize(q);
    /// assert_eq!(r.to_string(), "28.25");
    /// ```
    fn quantize(self, quant: Rhs) -> Self::Output;
}

impl<T, Q> Quantize<Q> for T
where
    Q: Copy,
    T: DivRounded<Q>,
    <T as DivRounded<Q>>::Output: Mul<Q>,
{
    type Output = <<T as DivRounded<Q>>::Output as Mul<Q>>::Output;

    #[inline(always)]
    fn quantize(self, quant: Q) -> Self::Output {
        self.div_rounded(quant, 0) * quant
    }
}

#[cfg(test)]
mod div_rounded_int_by_int_tests {
    use super::*;
    use crate::Decimal;

    #[test]
    fn test_quantize_int_by_int() {
        let i = 42_i32;
        let j = 15_i32;
        let q = i.quantize(j);
        assert_eq!(q.coefficient(), 45);
        assert_eq!(q.n_frac_digits(), 0);
        assert_eq!(q.coefficient(), i.quantize(&j).coefficient());
        assert_eq!(q.coefficient(), (&i).quantize(j).coefficient());
        assert_eq!(q.coefficient(), (&i).quantize(&j).coefficient());
    }

    #[test]
    fn test_quantize_int_by_dec() {
        let i = 43_u8;
        let d = Decimal::new_raw(75, 2);
        let q = i.quantize(d);
        assert_eq!(q.coefficient(), 4275);
        assert_eq!(q.n_frac_digits(), d.n_frac_digits());
        assert_eq!(q.coefficient(), i.quantize(&d).coefficient());
        assert_eq!(q.coefficient(), (&i).quantize(d).coefficient());
        assert_eq!(q.coefficient(), (&i).quantize(&d).coefficient());
    }

    #[test]
    fn test_quantize_dec_by_int() {
        let d = Decimal::new_raw(75327, 2);
        let i = 413_u64;
        let q = d.quantize(i);
        assert_eq!(q.coefficient(), 826);
        assert_eq!(q.n_frac_digits(), 0);
        assert_eq!(q.coefficient(), d.quantize(&i).coefficient());
        assert_eq!(q.coefficient(), (&d).quantize(i).coefficient());
        assert_eq!(q.coefficient(), (&d).quantize(&i).coefficient());
    }

    #[test]
    fn test_quantize_dec_by_dec() {
        let x = Decimal::new_raw(4375, 2);
        let y = Decimal::new_raw(125, 1);
        let q = x.quantize(y);
        assert_eq!(q.coefficient(), 500);
        assert_eq!(q.n_frac_digits(), y.n_frac_digits());
        let x = Decimal::new_raw(437499, 4);
        let y = Decimal::new_raw(125, 1);
        let q = x.quantize(y);
        assert_eq!(q.coefficient(), 375);
        assert_eq!(q.n_frac_digits(), y.n_frac_digits());
        assert_eq!(q.coefficient(), x.quantize(&y).coefficient());
        assert_eq!(q.coefficient(), (&x).quantize(y).coefficient());
        assert_eq!(q.coefficient(), (&x).quantize(&y).coefficient());
    }
}