rust_fixed_point_decimal/binops/
div.rs1use std::ops::{Div, DivAssign};
11
12use num::{integer::div_mod_floor, One, Zero};
13use rust_fixed_point_decimal_core::mul_pow_ten;
14
15use crate::{
16 prec_constraints::{PrecLimitCheck, True},
17 Decimal, DecimalError, MAX_PREC,
18};
19
20impl<const P: u8, const Q: u8> Div<Decimal<Q>> for Decimal<P>
21where
22 PrecLimitCheck<{ P <= MAX_PREC }>: True,
23 PrecLimitCheck<{ Q <= MAX_PREC }>: True,
24{
25 type Output = Decimal<9>;
26
27 fn div(self, other: Decimal<Q>) -> Self::Output {
28 if other.eq_zero() {
29 panic!("{}", DecimalError::DivisionByZero);
30 }
31 if other.eq_one() {
32 return Self::Output {
33 coeff: mul_pow_ten(self.coeff, MAX_PREC - P),
34 };
35 }
36 let r = MAX_PREC + Q - P;
37 let (quot, rem) =
39 div_mod_floor(mul_pow_ten(self.coeff, r), other.coeff);
40 if rem != 0 {
41 panic!("{}", DecimalError::PrecLimitExceeded);
42 }
43 Self::Output { coeff: quot }
44 }
45}
46
47forward_ref_binop!(impl Div, div);
48
49#[cfg(test)]
50mod div_decimal_tests {
51 use super::*;
52
53 #[test]
54 fn test_div() {
55 let x = Decimal::<0>::new_raw(17);
56 let y = Decimal::<2>::new_raw(-200);
57 let z = x / y;
58 assert_eq!(z.coeff, -8500000000);
59 let x = Decimal::<8>::new_raw(17);
60 let y = Decimal::<0>::new_raw(2);
61 let z = x / y;
62 assert_eq!(z.coeff, 85);
63 let x = Decimal::<2>::new_raw(12345678901234567890);
64 let y = Decimal::<6>::new_raw(244140625);
65 let z = x / y;
66 assert_eq!(z.coeff, 505679007794567900774400);
67 }
68
69 #[test]
70 fn test_div_by_one() {
71 let x = Decimal::<5>::new_raw(17);
72 let y = Decimal::<2>::ONE;
73 let z = x / y;
74 assert_eq!(z.coeff, 170000);
75 let y = Decimal::<9>::ONE;
76 let z = x / y;
77 assert_eq!(z.coeff, 170000);
78 }
79
80 #[test]
81 #[should_panic]
82 fn test_div_by_zero() {
83 let x = Decimal::<5>::new_raw(17);
84 let y = Decimal::<2>::ZERO;
85 let _z = x / y;
86 }
87
88 #[test]
89 #[should_panic]
90 fn test_div_prec_limit_exceeded() {
91 let x = Decimal::<9>::new_raw(17);
92 let y = Decimal::<0>::new_raw(2);
93 let _z = x / y;
94 }
95
96 #[test]
97 #[should_panic]
98 fn test_div_overflow() {
99 let x = Decimal::<0>::new_raw(mul_pow_ten(17, 20));
100 let y = Decimal::<9>::new_raw(2);
101 let _z = x / y;
102 }
103
104 #[test]
105 fn test_div_ref() {
106 let x = Decimal::<3>::new_raw(12345);
107 let y = Decimal::<1>::new_raw(12345);
108 let z = x / y;
109 assert_eq!(z.coeff, (&x / y).coeff);
110 assert_eq!(z.coeff, (x / &y).coeff);
111 assert_eq!(z.coeff, (&x / &y).coeff);
112 }
113}
114
115macro_rules! impl_div_decimal_and_int {
116 () => {
117 impl_div_decimal_and_int!(u8, i8, u16, i16, u32, i32, u64, i64, i128);
118 };
119 ($($t:ty),*) => {
120 $(
121 impl<const P: u8> Div<$t> for Decimal<P>
122 where
123 PrecLimitCheck<{ P <= MAX_PREC }>: True,
124 {
125 type Output = Decimal<9>;
126
127 fn div(self, other: $t) -> Self::Output {
128 if other.is_zero() {
129 panic!("{}", DecimalError::DivisionByZero);
130 }
131 if other.is_one() {
132 return Self::Output {
133 coeff: mul_pow_ten(self.coeff, MAX_PREC - P),
134 };
135 }
136 let r = MAX_PREC - P;
137 let (quot, rem) =
138 div_mod_floor(mul_pow_ten(self.coeff, r), other as i128);
139 if rem != 0 {
140 panic!("{}", DecimalError::PrecLimitExceeded);
141 }
142 Self::Output { coeff: quot }
143 }
144 }
145
146 impl<const P: u8> Div<Decimal<P>> for $t
147 where
148 PrecLimitCheck<{ P <= MAX_PREC }>: True,
149 {
150 type Output = Decimal<9>;
151
152 fn div(self, other: Decimal<P>) -> Self::Output {
153 if other.eq_zero() {
154 panic!("{}", DecimalError::DivisionByZero);
155 }
156 if other.eq_one() {
157 return Self::Output {
158 coeff: mul_pow_ten(self as i128, MAX_PREC),
159 };
160 }
161 let r = MAX_PREC + P;
162 let (quot, rem) =
163 div_mod_floor(mul_pow_ten(self as i128, r), other.coeff);
164 if rem != 0 {
165 panic!("{}", DecimalError::PrecLimitExceeded);
166 }
167 Self::Output { coeff: quot }
168 }
169 }
170 )*
171 }
172}
173
174impl_div_decimal_and_int!();
175forward_ref_binop_decimal_int!(impl Div, div);
176
177#[cfg(test)]
178#[allow(clippy::neg_multiply)]
179mod div_integer_tests {
180 use num::{One, Zero};
181 use rust_fixed_point_decimal_core::ten_pow;
182
183 use super::*;
184
185 macro_rules! gen_div_integer_tests {
186 ($func:ident, $t:ty, $p:expr, $coeff:expr) => {
187 #[test]
188 fn $func() {
189 let d = Decimal::<$p>::new_raw($coeff);
190 let i: $t = 10;
191 let r = d / i;
192 assert_eq!(r.precision(), MAX_PREC);
193 assert_eq!(
194 r.coeff,
195 $coeff * ten_pow(MAX_PREC - $p) / i as i128
196 );
197 assert_eq!(r.coeff, (&d / i).coeff);
198 assert_eq!(r.coeff, (d / &i).coeff);
199 assert_eq!(r.coeff, (&d / &i).coeff);
200 let z = i / d;
201 assert_eq!(z.precision(), MAX_PREC);
202 assert_eq!(
203 z.coeff,
204 i as i128 * ten_pow(MAX_PREC + $p) / $coeff
205 );
206 assert_eq!(z.coeff, (&i / d).coeff);
207 assert_eq!(z.coeff, (i / &d).coeff);
208 assert_eq!(z.coeff, (&i / &d).coeff);
209 }
210 };
211 }
212
213 gen_div_integer_tests!(test_div_u8, u8, 2, -1);
214 gen_div_integer_tests!(test_div_i8, i8, 0, 250);
215 gen_div_integer_tests!(test_div_u16, u16, 4, 80);
216 gen_div_integer_tests!(test_div_i16, i16, 4, 390625);
217 gen_div_integer_tests!(test_div_u32, u32, 1, 10);
218 gen_div_integer_tests!(test_div_i32, i32, 9, -1000);
219 gen_div_integer_tests!(test_div_u64, u64, 3, 20);
220 gen_div_integer_tests!(test_div_i64, i64, 7, -488281250);
221
222 #[test]
223 fn test_div_i128() {
224 let coeff = 2002_i128;
225 let d = Decimal::<4>::new_raw(coeff);
226 let i = 5005_i128;
227 let r = d / i;
228 assert_eq!(r.precision(), MAX_PREC);
229 assert_eq!(r.coeff, coeff * 100000 / i);
230 assert_eq!(r.coeff, (&d / i).coeff);
231 assert_eq!(r.coeff, (d / &i).coeff);
232 assert_eq!(r.coeff, (&d / &i).coeff);
233 let z = i / d;
234 assert_eq!(z.precision(), MAX_PREC);
235 assert_eq!(z.coeff, i * ten_pow(13) / coeff);
236 assert_eq!(z.coeff, (&i / d).coeff);
237 assert_eq!(z.coeff, (i / &d).coeff);
238 assert_eq!(z.coeff, (&i / &d).coeff);
239 }
240
241 #[test]
242 fn test_div_decimal_by_int_one() {
243 let x = Decimal::<5>::new_raw(17);
244 let y = i64::one();
245 let z = x / y;
246 assert_eq!(z.coeff, 170000);
247 let y = u8::one();
248 let z = x / y;
249 assert_eq!(z.coeff, 170000);
250 }
251
252 #[test]
253 fn test_div_int_by_decimal_one() {
254 let x = 17;
255 let y = Decimal::<5>::ONE;
256 let z: Decimal<9> = x / y;
257 assert_eq!(z.coeff, 17000000000);
258 let x = u64::one();
259 let z = x / y;
260 assert_eq!(z.coeff, 1000000000);
261 }
262
263 #[test]
264 #[should_panic]
265 fn test_div_decimal_by_int_zero() {
266 let x = Decimal::<5>::new_raw(17);
267 let y = i32::zero();
268 let _z = x / y;
269 }
270
271 #[test]
272 #[should_panic]
273 fn test_div_int_by_decimal_zero() {
274 let x = 25;
275 let y = Decimal::<3>::ZERO;
276 let _z = x / y;
277 }
278
279 #[test]
280 #[should_panic]
281 fn test_div_decimal_by_int_prec_limit_exceeded() {
282 let x = Decimal::<2>::new_raw(17);
283 let y = 3;
284 let _z = x / y;
285 }
286
287 #[test]
288 #[should_panic]
289 fn test_div_int_by_decimal_prec_limit_exceeded() {
290 let x = 3;
291 let y = Decimal::<2>::new_raw(17);
292 let _z = x / y;
293 }
294
295 #[test]
296 #[should_panic]
297 fn test_div_int_by_decimal_overflow() {
298 let x = mul_pow_ten(17, 20);
299 let y = Decimal::<9>::new_raw(2);
300 let _z = x / y;
301 }
302}
303
304forward_op_assign!(impl DivAssign, div_assign, Div, div);
305
306#[cfg(test)]
307mod div_assign_tests {
308 use super::*;
309
310 #[test]
311 fn test_div_assign_decimal() {
312 let mut x = Decimal::<9>::new_raw(1234567890);
313 x /= Decimal::<3>::new_raw(5000);
314 assert_eq!(x.coeff, 123456789 * 2);
315 }
316
317 #[test]
318 fn test_div_assign_int() {
319 let mut x = Decimal::<9>::new_raw(1234567890);
320 x /= -10_i64;
321 assert_eq!(x.coeff, -123456789);
322 }
323
324 #[test]
325 #[should_panic]
326 fn test_div_assign_decimal_by_int_zero() {
327 let mut x = Decimal::<9>::new_raw(17);
328 let y = i32::zero();
329 x /= y;
330 }
331
332 #[test]
333 #[should_panic]
334 fn test_div_assign_decimal_by_decimal_zero() {
335 let mut x = Decimal::<9>::new_raw(25);
336 let y = Decimal::<3>::ZERO;
337 x /= y;
338 }
339
340 #[test]
341 #[should_panic]
342 fn test_div_assign_decimal_by_int_prec_limit_exceeded() {
343 let mut x = Decimal::<9>::new_raw(17);
344 let y = 3;
345 x /= y;
346 }
347
348 #[test]
349 #[should_panic]
350 fn test_div_assign_decimal_by_decimal_prec_limit_exceeded() {
351 let mut x = Decimal::<9>::new_raw(17);
352 let y = Decimal::<4>::new_raw(50000);
353 x /= y;
354 }
355}