rust_fixed_point_decimal/binops/
mul_rounded.rs1use std::cmp::Ordering;
11
12use rust_fixed_point_decimal_core::ten_pow;
13
14use crate::{
15 prec_constraints::{PrecLimitCheck, True},
16 rounding::div_i128_rounded,
17 Decimal, MAX_PREC,
18};
19
20pub trait MulRounded<Rhs, Result = Self> {
22 fn mul_rounded(self, rhs: Rhs) -> Result;
24}
25
26impl<const P: u8, const Q: u8, const R: u8> MulRounded<Decimal<Q>, Decimal<R>>
27 for Decimal<P>
28where
29 PrecLimitCheck<{ P <= MAX_PREC }>: True,
30 PrecLimitCheck<{ Q <= MAX_PREC }>: True,
31 PrecLimitCheck<{ R <= MAX_PREC }>: True,
32{
33 #[inline(always)]
34 fn mul_rounded(self, other: Decimal<Q>) -> Decimal<R> {
35 match R.cmp(&(P + Q)) {
36 Ordering::Equal => Decimal::<R> {
37 coeff: self.coeff * other.coeff,
38 },
39 Ordering::Less => Decimal::<R> {
40 coeff: div_i128_rounded(
41 self.coeff * other.coeff,
42 ten_pow(P + Q - R),
43 None,
44 ),
45 },
46 Ordering::Greater => Decimal::<R> {
47 coeff: self.coeff * other.coeff * ten_pow(R - P - Q),
48 },
49 }
50 }
51}
52
53forward_ref_binop_rounded!(impl MulRounded, mul_rounded);
54
55#[cfg(test)]
56mod mul_rounded_decimal_tests {
57 use super::*;
58
59 #[test]
60 fn test_mul_rounded_less_prec() {
61 let x = Decimal::<2>::new_raw(12345);
62 let z: Decimal<2> = x.mul_rounded(x);
63 assert_eq!(z.coeff, 1523990);
64 let y = Decimal::<4>::new_raw(5781);
65 let z: Decimal<1> = x.mul_rounded(y);
66 assert_eq!(z.coeff, 714);
67 let z: Decimal<1> = y.mul_rounded(x);
68 assert_eq!(z.coeff, 714);
69 }
70
71 #[test]
72 fn test_mul_rounded_no_adj_needed() {
73 let x = Decimal::<2>::new_raw(12345);
74 let z: Decimal<4> = x.mul_rounded(x);
75 assert_eq!(z.coeff, 152399025);
76 let y = Decimal::<4>::new_raw(5781);
77 let z: Decimal<6> = x.mul_rounded(y);
78 assert_eq!(z.coeff, 71366445);
79 let z: Decimal<6> = y.mul_rounded(x);
80 assert_eq!(z.coeff, 71366445);
81 }
82
83 #[test]
84 fn test_mul_rounded_greater_prec() {
85 let x = Decimal::<2>::new_raw(12345);
86 let z: Decimal<6> = x.mul_rounded(x);
87 assert_eq!(z.coeff, 15239902500);
88 let y = Decimal::<4>::new_raw(5781);
89 let z: Decimal<7> = x.mul_rounded(y);
90 assert_eq!(z.coeff, 713664450);
91 let z: Decimal<9> = y.mul_rounded(x);
92 assert_eq!(z.coeff, 71366445000);
93 }
94
95 #[test]
96 fn test_mul_rounded_ref() {
97 let x = Decimal::<3>::new_raw(12345);
98 let y = Decimal::<1>::new_raw(12345);
99 let z: Decimal<2> = x.mul_rounded(y);
100 let a: Decimal<2> = MulRounded::mul_rounded(&x, y);
101 assert_eq!(a.coeff, z.coeff);
102 let a: Decimal<2> = MulRounded::mul_rounded(x, &y);
103 assert_eq!(a.coeff, z.coeff);
104 let a: Decimal<2> = MulRounded::mul_rounded(&x, &y);
105 assert_eq!(a.coeff, z.coeff);
106 }
107}