rust_fixed_point_decimal/binops/
mul.rs1use std::ops::{Mul, MulAssign};
11
12use crate::{
13 binops::const_sum_u8,
14 prec_constraints::{PrecLimitCheck, True},
15 Decimal, MAX_PREC,
16};
17
18impl<const P: u8> Decimal<P>
23where
24 PrecLimitCheck<{ P <= MAX_PREC }>: True,
26{
27 #[inline(always)]
29 pub fn one() -> Self {
30 Self::ONE
31 }
32
33 #[inline(always)]
35 pub fn is_one(&self) -> bool {
36 self.eq_one()
37 }
38}
39
40#[cfg(test)]
41mod one_tests {
42 use super::*;
43
44 #[test]
45 fn test_one() {
46 assert!(Decimal::<0>::is_one(&Decimal::<0>::one()));
47 assert!(Decimal::<1>::is_one(&Decimal::<1>::one()));
48 assert!(Decimal::<2>::is_one(&Decimal::<2>::one()));
49 assert!(Decimal::<3>::is_one(&Decimal::<3>::one()));
50 assert!(Decimal::<4>::is_one(&Decimal::<4>::one()));
51 assert!(Decimal::<5>::is_one(&Decimal::<5>::one()));
52 assert!(Decimal::<6>::is_one(&Decimal::<6>::one()));
53 assert!(Decimal::<7>::is_one(&Decimal::<7>::one()));
54 assert!(Decimal::<8>::is_one(&Decimal::<8>::one()));
55 assert!(Decimal::<9>::is_one(&Decimal::<9>::one()));
56 }
57}
58
59impl<const P: u8, const Q: u8> Mul<Decimal<Q>> for Decimal<P>
60where
61 PrecLimitCheck<{ P <= MAX_PREC }>: True,
62 PrecLimitCheck<{ Q <= MAX_PREC }>: True,
63 PrecLimitCheck<{ (const_sum_u8(P, Q)) <= MAX_PREC }>: True,
64{
65 type Output = Decimal<{ const_sum_u8(P, Q) }>;
66
67 #[inline(always)]
68 fn mul(self, other: Decimal<Q>) -> Self::Output {
69 Self::Output {
70 coeff: self.coeff * other.coeff,
71 }
72 }
73}
74
75forward_ref_binop!(impl Mul, mul);
76
77#[cfg(test)]
78mod mul_decimal_tests {
79 use super::*;
80
81 #[test]
82 fn test_mul_same_prec() {
83 let x = Decimal::<4>::new_raw(1234567890);
84 let y = x * x;
85 assert_eq!(y.precision(), 8);
86 assert_eq!(y.coeff, x.coeff * x.coeff);
87 let z = x * Decimal::<4>::NEG_ONE;
88 assert_eq!(z.precision(), 8);
89 assert_eq!(z.coeff, -x.coeff * 10000);
90 }
91
92 #[test]
93 fn test_mul_different_prec() {
94 let x = Decimal::<5>::new_raw(1234567890);
95 let y = Decimal::<1>::new_raw(890);
96 let z = x * y;
97 assert_eq!(z.precision(), 6);
98 assert_eq!(z.coeff, x.coeff * y.coeff);
99 let z = y * x;
100 assert_eq!(z.precision(), 6);
101 assert_eq!(z.coeff, x.coeff * y.coeff);
102 let z = x * Decimal::<3>::NEG_ONE;
103 assert_eq!(z.precision(), 8);
104 assert_eq!(z.coeff, -x.coeff * 1000);
105 }
106
107 #[test]
108 #[should_panic]
109 fn test_mul_pos_overflow() {
110 let x = Decimal::<4>::new_raw(i128::MAX / 4 + 1);
111 let _y = x * Decimal::<4>::TWO;
112 }
113
114 #[test]
115 #[should_panic]
116 fn test_mul_neg_overflow() {
117 let x = Decimal::<2>::new_raw(i128::MIN);
118 let _y = x * Decimal::<2>::NEG_ONE;
119 }
120
121 #[test]
122 fn test_mul_ref() {
123 let x = Decimal::<3>::new_raw(12345);
124 let y = Decimal::<1>::new_raw(12345);
125 let z = x * y;
126 assert_eq!(z.coeff, (&x * y).coeff);
127 assert_eq!(z.coeff, (x * &y).coeff);
128 assert_eq!(z.coeff, (&x * &y).coeff);
129 }
130}
131
132macro_rules! impl_mul_decimal_and_int {
133 () => {
134 impl_mul_decimal_and_int!(u8, i8, u16, i16, u32, i32, u64, i64, i128);
135 };
136 ($($t:ty),*) => {
137 $(
138 impl<const P: u8> Mul<$t> for Decimal<P>
139 where
140 PrecLimitCheck<{ P <= MAX_PREC }>: True,
141 {
142 type Output = Decimal<P>;
143
144 #[inline(always)]
145 fn mul(self, other: $t) -> Self::Output {
146 Self::Output{
147 coeff: self.coeff * other as i128
148 }
149 }
150 }
151
152 impl<const P: u8> Mul<Decimal<P>> for $t
153 where
154 PrecLimitCheck<{ P <= MAX_PREC }>: True,
155 {
156 type Output = Decimal<P>;
157
158 #[inline(always)]
159 fn mul(self, other: Decimal<P>) -> Self::Output {
160 Self::Output{
161 coeff: self as i128 * other.coeff
162 }
163 }
164 }
165 )*
166 }
167}
168
169impl_mul_decimal_and_int!();
170forward_ref_binop_decimal_int!(impl Mul, mul);
171
172#[cfg(test)]
173#[allow(clippy::neg_multiply)]
174mod mul_integer_tests {
175 use super::*;
176
177 macro_rules! gen_mul_integer_tests {
178 ($func:ident, $t:ty, $p:expr, $coeff:expr) => {
179 #[test]
180 fn $func() {
181 let d = Decimal::<$p>::new_raw($coeff);
182 let i = <$t>::MAX;
183 let r = d * i;
184 assert_eq!(r.precision(), d.precision());
185 assert_eq!(r.coeff, i as i128 * $coeff);
186 assert_eq!(r.coeff, (&d * i).coeff);
187 assert_eq!(r.coeff, (d * &i).coeff);
188 assert_eq!(r.coeff, (&d * &i).coeff);
189 let z = i * d;
190 assert_eq!(z.precision(), r.precision());
191 assert_eq!(z.coeff, r.coeff);
192 assert_eq!(z.coeff, (&i * d).coeff);
193 assert_eq!(z.coeff, (i * &d).coeff);
194 assert_eq!(z.coeff, (&i * &d).coeff);
195 }
196 };
197 }
198
199 gen_mul_integer_tests!(test_mul_u8, u8, 2, -1);
200 gen_mul_integer_tests!(test_mul_i8, i8, 0, 123);
201 gen_mul_integer_tests!(test_mul_u16, u16, 4, 11);
202 gen_mul_integer_tests!(test_mul_i16, i16, 4, 1234567);
203 gen_mul_integer_tests!(test_mul_u32, u32, 1, 0);
204 gen_mul_integer_tests!(test_mul_i32, i32, 9, -1234);
205 gen_mul_integer_tests!(test_mul_u64, u64, 3, 321);
206 gen_mul_integer_tests!(test_mul_i64, i64, 7, -12345678901234567890);
207
208 #[test]
209 fn test_mul_i128() {
210 let coeff = 748_i128;
211 let d = Decimal::<2>::new_raw(coeff);
212 let i = 12345_i128;
213 let r = d * i;
214 assert_eq!(r.precision(), d.precision());
215 assert_eq!(r.coeff, i * coeff);
216 assert_eq!(r.coeff, (&d * i).coeff);
217 assert_eq!(r.coeff, (d * &i).coeff);
218 assert_eq!(r.coeff, (&d * &i).coeff);
219 let z = i * d;
220 assert_eq!(z.precision(), r.precision());
221 assert_eq!(z.coeff, r.coeff);
222 assert_eq!(z.coeff, (&i * d).coeff);
223 assert_eq!(z.coeff, (i * &d).coeff);
224 assert_eq!(z.coeff, (&i * &d).coeff);
225 }
226}
227
228forward_op_assign!(impl MulAssign, mul_assign, Mul, mul);
229
230#[cfg(test)]
231mod mul_assign_tests {
232 use super::*;
233
234 #[test]
235 fn test_mul_assign_decimal() {
236 let mut x = Decimal::<2>::new_raw(123456);
237 let y = Decimal::<0>::TWO;
238 x *= y;
239 assert_eq!(x.coeff, 123456_i128 * 2);
240 let z = &y;
241 x *= z;
242 assert_eq!(x.coeff, 123456_i128 * 4);
243 }
244
245 #[test]
246 fn test_mul_assign_int() {
247 let mut x = Decimal::<2>::new_raw(123456);
248 x *= 2_i8;
249 assert_eq!(x.coeff, 123456_i128 * 2);
250 x *= &-1234567890_i128;
251 assert_eq!(x.coeff, 123456_i128 * 2 * -1234567890_i128);
252 }
253
254 #[test]
255 #[should_panic]
256 fn test_mul_assign_pos_overflow() {
257 let mut x = Decimal::<4>::new_raw(i128::MAX / 2 + 1);
258 x *= 2;
259 }
260
261 #[test]
262 #[should_panic]
263 fn test_mul_assign_neg_overflow() {
264 let mut x = Decimal::<2>::new_raw(i128::MIN / 5 - 1);
265 x *= 5;
266 }
267}