fpdec/binops/
div_rounded.rs

1// ---------------------------------------------------------------------------
2// Copyright:   (c) 2021 ff. Michael Amrhein (michael@adrhinum.de)
3// License:     This program is part of a larger application. For license
4//              details please read the file LICENSE.TXT provided together
5//              with the application.
6// ---------------------------------------------------------------------------
7// $Source$
8// $Revision$
9
10use core::cmp::Ordering;
11
12use fpdec_core::{
13    checked_mul_pow_ten, i128_div_rounded, i128_shifted_div_rounded, ten_pow,
14    MAX_N_FRAC_DIGITS,
15};
16
17use crate::{Decimal, DecimalError};
18
19const MAGN_I128_MAX: u8 = 38;
20
21/// Division giving a result rounded to fit a given number of fractional
22/// digits.
23pub trait DivRounded<Rhs = Self> {
24    /// The resulting type after applying `div_rounded`.
25    type Output;
26
27    /// Returns `self` / `rhs`, rounded to `n_frac_digits`, according to the
28    /// current [RoundingMode](crate::RoundingMode).
29    ///
30    /// # Panics
31    ///
32    /// Panics if `rhs` equals zero or the resulting value can not be
33    /// represented by `Self::Output`!
34    ///
35    /// # Examples
36    ///
37    /// ```rust
38    /// # use fpdec::{Dec, Decimal, DivRounded};
39    /// let divident = -322_i32;
40    /// let divisor = 3_i32;
41    /// let res = divident.div_rounded(divisor, 0);
42    /// assert_eq!(res.to_string(), "-107");
43    /// let d = Dec!(28.27093);
44    /// let q = 5_u32;
45    /// let r = d.div_rounded(q, 4);
46    /// assert_eq!(r.to_string(), "5.6542");
47    /// let q = Dec!(0.03);
48    /// let r = d.div_rounded(q, 3);
49    /// assert_eq!(r.to_string(), "942.364");
50    /// ```
51    fn div_rounded(self, rhs: Rhs, n_frac_digits: u8) -> Self::Output;
52}
53
54#[allow(clippy::integer_division)]
55pub(crate) fn checked_div_rounded(
56    divident_coeff: i128,
57    divident_n_frac_digits: u8,
58    divisor_coeff: i128,
59    divisor_n_frac_digits: u8,
60    n_frac_digits: u8,
61) -> Option<i128> {
62    let mut shift = n_frac_digits + divisor_n_frac_digits;
63    match divident_n_frac_digits.cmp(&shift) {
64        Ordering::Equal => {
65            Some(i128_div_rounded(divident_coeff, divisor_coeff, None))
66        }
67        Ordering::Less => {
68            // divident coeff needs to be shifted
69            shift -= divident_n_frac_digits;
70            // 0 < shift <= 36
71            if let Some(shifted_divident) =
72                checked_mul_pow_ten(divident_coeff, shift)
73            {
74                Some(i128_div_rounded(shifted_divident, divisor_coeff, None))
75            } else {
76                i128_shifted_div_rounded(
77                    divident_coeff,
78                    shift,
79                    divisor_coeff,
80                    None,
81                )
82            }
83        }
84        Ordering::Greater => {
85            // divisor coeff needs to be shifted, but instead of calculating
86            // divident / (divisor * 10 ^ shift)
87            // we can calculate
88            // (divident / divisor) / 10 ^ shift
89            // thus avoiding i128 overflow.
90            // divident_n_frac_digits > shift
91            shift = divident_n_frac_digits - shift;
92            // shift < divident_n_frac_digits => shift < 18 => ten_pow(shift)
93            // is safe
94            Some(i128_div_rounded(
95                divident_coeff / divisor_coeff,
96                ten_pow(shift),
97                None,
98            ))
99        }
100    }
101}
102
103impl DivRounded<Self> for Decimal {
104    type Output = Self;
105
106    fn div_rounded(self, rhs: Self, n_frac_digits: u8) -> Self::Output {
107        #[allow(clippy::manual_assert)]
108        if n_frac_digits > MAX_N_FRAC_DIGITS {
109            panic!("{}", DecimalError::MaxNFracDigitsExceeded);
110        }
111        #[allow(clippy::manual_assert)]
112        if rhs.eq_zero() {
113            panic!("{}", DecimalError::DivisionByZero);
114        }
115        if self.eq_zero() {
116            return Self::ZERO;
117        }
118        if let Some(coeff) = checked_div_rounded(
119            self.coeff,
120            self.n_frac_digits,
121            rhs.coeff,
122            rhs.n_frac_digits,
123            n_frac_digits,
124        ) {
125            Self::Output {
126                coeff,
127                n_frac_digits,
128            }
129        } else {
130            panic!("{}", DecimalError::InternalOverflow);
131        }
132    }
133}
134
135forward_ref_binop_rounded!(impl DivRounded, div_rounded);
136
137#[cfg(test)]
138mod div_rounded_decimal_tests {
139    use fpdec_core::mul_pow_ten;
140
141    use super::*;
142
143    #[test]
144    fn test_div_rounded() {
145        let x = Decimal::new_raw(17, 0);
146        let y = Decimal::new_raw(-201, 2);
147        let z = x.div_rounded(y, 2);
148        assert_eq!(z.coefficient(), -846);
149        assert_eq!(z.n_frac_digits(), 2);
150        let x = Decimal::new_raw(17654321, 8);
151        let y = Decimal::new_raw(204, 3);
152        let z = x.div_rounded(y, 2);
153        assert_eq!(z.coefficient(), 87);
154        assert_eq!(z.n_frac_digits(), 2);
155        let x = Decimal::new_raw(12345678901234567890, 2);
156        let y = Decimal::new_raw(244140625, 6);
157        let z = x.div_rounded(y, 9);
158        assert_eq!(z.coefficient(), 505679007794567900774400);
159        assert_eq!(z.n_frac_digits(), 9);
160        let x = Decimal::new_raw(1234567, 5);
161        let y = Decimal::new_raw(625, 2);
162        let z = x.div_rounded(y, 3);
163        assert_eq!(z.coefficient(), 1975);
164        assert_eq!(z.n_frac_digits(), 3);
165    }
166
167    #[test]
168    fn test_div_rounded_to_int() {
169        let x = Decimal::new_raw(17, 0);
170        let y = Decimal::new_raw(200, 2);
171        let z = x.div_rounded(y, 0);
172        assert_eq!(z.coefficient(), 8);
173        assert_eq!(z.n_frac_digits(), 0);
174        let y = Decimal::new_raw(3, 0);
175        let z = x.div_rounded(y, 0);
176        assert_eq!(z.coefficient(), 6);
177        let x = Decimal::new_raw(170000, 4);
178        let y = Decimal::new_raw(3, 0);
179        let z = x.div_rounded(y, 0);
180        assert_eq!(z.coefficient(), 6);
181    }
182
183    #[test]
184    fn test_div_zero_rounded() {
185        let x = Decimal::new_raw(0, 5);
186        let y = Decimal::new_raw(17, 1);
187        let z = x.div_rounded(y, 3);
188        assert_eq!(z.coefficient(), 0);
189        assert_eq!(z.n_frac_digits(), 0);
190        let z = x.div_rounded(y, 18);
191        assert_eq!(z.coefficient(), 0);
192        assert_eq!(z.n_frac_digits(), 0);
193    }
194
195    #[test]
196    fn test_div_rounded_by_one() {
197        let x = Decimal::new_raw(17, 5);
198        let y = Decimal::ONE;
199        let z = x.div_rounded(y, 4);
200        assert_eq!(z.coefficient(), 2);
201        assert_eq!(z.n_frac_digits(), 4);
202        let y = Decimal::new_raw(1000000000, 9);
203        let z = x.div_rounded(y, 6);
204        assert_eq!(z.coefficient(), 170);
205        assert_eq!(z.n_frac_digits(), 6);
206    }
207
208    // corner case: shifting divident overflows, stepwise algorithm must be
209    // used
210    #[test]
211    fn test_div_rounded_stepwise() {
212        let x = Decimal::new_raw(mul_pow_ten(13, 11), 1);
213        let y = Decimal::new_raw(20, 18);
214        let z = x.div_rounded(y, 10);
215        assert_eq!(z.coefficient(), 65000000000000000000000000000000000000);
216        assert_eq!(z.n_frac_digits(), 10);
217    }
218
219    #[test]
220    #[should_panic]
221    fn test_div_rounded_by_zero() {
222        let x = Decimal::new_raw(17, 5);
223        let y = Decimal::ZERO;
224        let _z = x.div_rounded(y, 5);
225    }
226
227    #[test]
228    #[should_panic]
229    fn test_div_rounded_overflow() {
230        let x = Decimal::new_raw(mul_pow_ten(17, 20), 0);
231        let y = Decimal::new_raw(2, 19);
232        let _z = x.div_rounded(y, 0);
233    }
234
235    #[test]
236    fn test_div_rounded_ref() {
237        let x = Decimal::new_raw(12345, 3);
238        let y = Decimal::new_raw(12345, 4);
239        let z = x.div_rounded(y, 2);
240        let a = DivRounded::div_rounded(&x, y, 2);
241        assert_eq!(a.coefficient(), z.coefficient());
242        let a = DivRounded::div_rounded(x, &y, 2);
243        assert_eq!(a.coefficient(), z.coefficient());
244        let a = DivRounded::div_rounded(&x, &y, 2);
245        assert_eq!(a.coefficient(), z.coefficient());
246    }
247}
248
249macro_rules! impl_div_rounded_decimal_and_int {
250    () => {
251        impl_div_rounded_decimal_and_int!(
252            u8, i8, u16, i16, u32, i32, u64, i64, i128
253        );
254    };
255    ($($t:ty),*) => {
256        $(
257        impl DivRounded<$t> for Decimal {
258            type Output = Self;
259
260            fn div_rounded(self, rhs: $t, n_frac_digits: u8) -> Self::Output {
261                if rhs == 0 {
262                    panic!("{}", DecimalError::DivisionByZero);
263                }
264                if self.eq_zero() {
265                    return Self::ZERO;
266                }
267                if let Some(coeff) = checked_div_rounded(
268                    self.coeff,
269                    self.n_frac_digits,
270                    i128::from(rhs),
271                    0_u8,
272                    n_frac_digits,
273                ) {
274                    Self::Output {
275                        coeff,
276                        n_frac_digits,
277                    }
278                } else {
279                    panic!("{}", DecimalError::InternalOverflow);
280                }
281            }
282        }
283
284        impl<'a> DivRounded<$t> for &'a Decimal
285        where
286            Decimal: DivRounded<$t>,
287        {
288            type Output = <Decimal as DivRounded<$t>>::Output;
289
290            #[inline(always)]
291            fn div_rounded(self, rhs: $t, n_frac_digits: u8) -> Self::Output {
292                DivRounded::div_rounded(*self, rhs, n_frac_digits)
293            }
294        }
295
296        impl DivRounded<&$t> for Decimal
297        where
298            Decimal: DivRounded<$t>,
299        {
300            type Output = <Decimal as DivRounded<$t>>::Output;
301
302            #[inline(always)]
303            fn div_rounded(self, rhs: &$t, n_frac_digits: u8) -> Self::Output {
304                DivRounded::div_rounded(self, *rhs, n_frac_digits)
305            }
306        }
307
308        impl DivRounded<&$t> for &Decimal
309        where
310            Decimal: DivRounded<$t>,
311        {
312            type Output = <Decimal as DivRounded<$t>>::Output;
313
314            #[inline(always)]
315            fn div_rounded(self, rhs: &$t, n_frac_digits: u8) -> Self::Output {
316                DivRounded::div_rounded(*self, *rhs, n_frac_digits)
317            }
318        }
319
320        impl DivRounded<Decimal> for $t {
321            type Output = Decimal;
322
323            fn div_rounded(self, rhs: Decimal, n_frac_digits: u8) -> Self::Output {
324                if rhs.eq_zero() {
325                    panic!("{}", DecimalError::DivisionByZero);
326                }
327                if self == 0 {
328                    return Decimal::ZERO;
329                }
330                if let Some(coeff) = checked_div_rounded(
331                    i128::from(self),
332                    0_u8,
333                    rhs.coeff,
334                    rhs.n_frac_digits,
335                    n_frac_digits,
336                ) {
337                    Self::Output {
338                        coeff,
339                        n_frac_digits,
340                    }
341                } else {
342                    panic!("{}", DecimalError::InternalOverflow);
343                }
344            }
345        }
346
347        impl<'a> DivRounded<Decimal> for &'a $t
348        where
349            $t: DivRounded<Decimal>,
350        {
351            type Output = <$t as DivRounded<Decimal>>::Output;
352
353            #[inline(always)]
354            fn div_rounded(self, rhs: Decimal, n_frac_digits: u8) -> Self::Output {
355                DivRounded::div_rounded(*self, rhs, n_frac_digits)
356            }
357        }
358
359        impl DivRounded<&Decimal> for $t
360        where
361            $t: DivRounded<Decimal>,
362        {
363            type Output = <$t as DivRounded<Decimal>>::Output;
364
365            #[inline(always)]
366            fn div_rounded(self, rhs: &Decimal, n_frac_digits: u8) -> Self::Output {
367                DivRounded::div_rounded(self, *rhs, n_frac_digits)
368            }
369        }
370
371        impl DivRounded<&Decimal> for &$t
372        where
373            $t: DivRounded<Decimal>,
374        {
375            type Output = <$t as DivRounded<Decimal>>::Output;
376
377            #[inline(always)]
378            fn div_rounded(self, rhs: &Decimal, n_frac_digits: u8) -> Self::Output {
379                DivRounded::div_rounded(*self, *rhs, n_frac_digits)
380            }
381        }
382        )*
383    }
384}
385
386impl_div_rounded_decimal_and_int!();
387
388#[cfg(test)]
389#[allow(clippy::neg_multiply)]
390mod div_rounded_decimal_by_int_tests {
391    use super::*;
392
393    macro_rules! gen_div_rounded_decimal_by_int_tests {
394        ($func:ident, $p:expr, $coeff:expr, $i:expr, $r:expr,
395         $res_coeff:expr) => {
396            #[test]
397            fn $func() {
398                let d = Decimal::new_raw($coeff, $p);
399                let i = $i;
400                let r = d.div_rounded(i, $r);
401                assert_eq!(r.coefficient(), $res_coeff);
402                assert_eq!(r.n_frac_digits(), $r);
403                let r = (&d).div_rounded(i, $r);
404                assert_eq!(r.coefficient(), $res_coeff);
405                assert_eq!(r.n_frac_digits(), $r);
406                let r = d.div_rounded(&i, $r);
407                assert_eq!(r.coefficient(), $res_coeff);
408                assert_eq!(r.n_frac_digits(), $r);
409                let r = (&d).div_rounded(&i, $r);
410                assert_eq!(r.coefficient(), $res_coeff);
411                assert_eq!(r.n_frac_digits(), $r);
412            }
413        };
414    }
415
416    gen_div_rounded_decimal_by_int_tests!(test_u8, 2, -1, 3_u8, 5, -333);
417    gen_div_rounded_decimal_by_int_tests!(test_i8, 0, -12, -3_i8, 5, 400000);
418    gen_div_rounded_decimal_by_int_tests!(test_u16, 2, -1, 3_u16, 5, -333);
419    gen_div_rounded_decimal_by_int_tests!(test_i16, 3, -12, -3_i16, 5, 400);
420    gen_div_rounded_decimal_by_int_tests!(
421        test_u32,
422        4,
423        u32::MAX as i128,
424        1_u32,
425        5,
426        u32::MAX as i128 * 10_i128
427    );
428    gen_div_rounded_decimal_by_int_tests!(
429        test_i32, 3, 12345, -328_i32, 5, -3764
430    );
431    gen_div_rounded_decimal_by_int_tests!(test_u64, 9, -1, 2_u64, 5, 0);
432    gen_div_rounded_decimal_by_int_tests!(
433        test_i64,
434        3,
435        u64::MAX as i128,
436        i64::MIN,
437        2,
438        0
439    );
440    gen_div_rounded_decimal_by_int_tests!(
441        test_i128,
442        0,
443        12345678901234567890,
444        987654321_i128,
445        5,
446        1249999988734375
447    );
448
449    #[test]
450    fn test_div_rounded_decimal_zero_by_int() {
451        let x = Decimal::new_raw(0, 3);
452        let y = 123_i64;
453        let z = x.div_rounded(y, 2);
454        assert_eq!(z.coefficient(), 0);
455        assert_eq!(z.n_frac_digits(), 0);
456    }
457
458    #[test]
459    fn test_div_rounded_int_zero_by_decimal() {
460        let x = 0_u32;
461        let y = Decimal::new_raw(1234567, 3);
462        let z = x.div_rounded(y, 13);
463        assert_eq!(z.coefficient(), 0);
464        assert_eq!(z.n_frac_digits(), 0);
465    }
466
467    #[test]
468    fn test_div_rounded_decimal_by_int_one() {
469        let x = Decimal::new_raw(17, 5);
470        let y = 1_i64;
471        let z = x.div_rounded(y, 5);
472        assert_eq!(z.coefficient(), 17);
473        assert_eq!(z.n_frac_digits(), 5);
474        let y = 1_u8;
475        let z = x.div_rounded(y, 7);
476        assert_eq!(z.coefficient(), 1700);
477        assert_eq!(z.n_frac_digits(), 7);
478        let y = 1_i32;
479        let z = x.div_rounded(y, 4);
480        assert_eq!(z.coefficient(), 2);
481        assert_eq!(z.n_frac_digits(), 4);
482    }
483
484    #[test]
485    fn test_div_rounded_int_by_decimal_one() {
486        let x = 17;
487        let y = Decimal::ONE;
488        let z: Decimal = x.div_rounded(y, 0);
489        assert_eq!(z.coefficient(), 17);
490        assert_eq!(z.n_frac_digits(), 0);
491        let x = 1_u64;
492        let y = Decimal::new_raw(1000, 3);
493        let z = x.div_rounded(y, 2);
494        assert_eq!(z.coefficient(), 100);
495        assert_eq!(z.n_frac_digits(), 2);
496    }
497
498    // corner case: shifting divident overflows, stepwise algorithm must be
499    // used
500    #[test]
501    fn test_div_rounded_stepwise() {
502        let x = Decimal::new_raw(i128::MAX, 0);
503        let y = Decimal::new_raw(20, 0);
504        let z = x.div_rounded(y, 1);
505        assert_eq!(z.coefficient(), (i128::MAX / 20) * 10 + 4);
506        assert_eq!(z.n_frac_digits(), 1);
507    }
508
509    #[test]
510    #[should_panic]
511    fn test_div_rounded_decimal_by_int_zero() {
512        let x = Decimal::new_raw(17, 3);
513        let y = 0_i64;
514        let _z = x.div_rounded(y, 5);
515    }
516}
517
518#[cfg(test)]
519#[allow(clippy::neg_multiply)]
520mod div_rounded_int_by_decimal_tests {
521    use super::*;
522
523    macro_rules! gen_div_rounded_int_by_decimal_tests {
524        ($func:ident, $p:expr, $coeff:expr, $i:expr, $r:expr,
525         $res_coeff:expr) => {
526            #[test]
527            fn $func() {
528                let d = Decimal::new_raw($coeff, $p);
529                let i = $i;
530                let r = i.div_rounded(d, $r);
531                assert_eq!(r.coefficient(), $res_coeff);
532                assert_eq!(r.n_frac_digits(), $r);
533                let r = (&i).div_rounded(d, $r);
534                assert_eq!(r.coefficient(), $res_coeff);
535                assert_eq!(r.n_frac_digits(), $r);
536                let r = i.div_rounded(&d, $r);
537                assert_eq!(r.coefficient(), $res_coeff);
538                assert_eq!(r.n_frac_digits(), $r);
539                let r = (&i).div_rounded(&d, $r);
540                assert_eq!(r.coefficient(), $res_coeff);
541                assert_eq!(r.n_frac_digits(), $r);
542            }
543        };
544    }
545
546    gen_div_rounded_int_by_decimal_tests!(test_u8, 2, -14, 3_u8, 5, -2142857);
547    gen_div_rounded_int_by_decimal_tests!(test_i8, 0, -12, -3_i8, 5, 25000);
548    gen_div_rounded_int_by_decimal_tests!(
549        test_u16, 2, -17, 3_u16, 5, -1764706
550    );
551    gen_div_rounded_int_by_decimal_tests!(test_i16, 3, -12, -3_i16, 2, 25000);
552    gen_div_rounded_int_by_decimal_tests!(
553        test_u32,
554        4,
555        u32::MAX as i128,
556        1_u32,
557        9,
558        2328
559    );
560    gen_div_rounded_int_by_decimal_tests!(
561        test_i32, 3, 12345, -328_i32, 5, -2656946
562    );
563    gen_div_rounded_int_by_decimal_tests!(
564        test_u64,
565        9,
566        -1,
567        2_u64,
568        5,
569        -200000000000000
570    );
571    gen_div_rounded_int_by_decimal_tests!(
572        test_i64,
573        3,
574        u64::MAX as i128,
575        i64::MIN,
576        2,
577        -50000
578    );
579    gen_div_rounded_int_by_decimal_tests!(
580        test_i128,
581        0,
582        1234567890,
583        987654321987654321_i128,
584        1,
585        8000000081
586    );
587
588    #[test]
589    #[should_panic]
590    fn test_div_rounded_int_by_decimal_zero() {
591        let x = 17_u16;
592        let y = Decimal::ZERO;
593        let _z = x.div_rounded(y, 5);
594    }
595
596    #[test]
597    #[should_panic]
598    fn test_div_rounded_int_by_decimal_non_normalized_zero() {
599        let x = -729_i32;
600        let y = Decimal::new_raw(0, 3);
601        let _z = x.div_rounded(y, 5);
602    }
603}
604
605macro_rules! impl_div_rounded_int_and_int {
606    () => {
607        impl_div_rounded_int_and_int!(
608            u8, i8, u16, i16, u32, i32, u64, i64, i128
609        );
610    };
611    ($($t:ty),*) => {
612        $(
613        impl DivRounded<$t> for $t {
614            type Output = Decimal;
615
616            fn div_rounded(self, rhs: $t, n_frac_digits: u8) -> Self::Output {
617                if rhs == 0 {
618                    panic!("{}", DecimalError::DivisionByZero);
619                }
620                if self == 0 {
621                    return Decimal::ZERO;
622                }
623                if let Some(coeff) = checked_div_rounded(
624                    i128::from(self),
625                    0_u8,
626                    i128::from(rhs),
627                    0_u8,
628                    n_frac_digits,
629                ) {
630                    Self::Output {
631                        coeff,
632                        n_frac_digits,
633                    }
634                } else {
635                    panic!("{}", DecimalError::InternalOverflow);
636                }
637            }
638        }
639
640        impl<'a> DivRounded<$t> for &'a $t
641        where
642            $t: DivRounded<$t>,
643        {
644            type Output = <$t as DivRounded<$t>>::Output;
645
646            #[inline(always)]
647            fn div_rounded(self, rhs: $t, n_frac_digits: u8) -> Self::Output {
648                DivRounded::div_rounded(*self, rhs, n_frac_digits)
649            }
650        }
651
652        impl DivRounded<&$t> for $t
653        where
654            $t: DivRounded<$t>,
655        {
656            type Output = <$t as DivRounded<$t>>::Output;
657
658            #[inline(always)]
659            fn div_rounded(self, rhs: &$t, n_frac_digits: u8) -> Self::Output {
660                DivRounded::div_rounded(self, *rhs, n_frac_digits)
661            }
662        }
663
664        impl DivRounded<&$t> for &$t
665        where
666            $t: DivRounded<$t>,
667        {
668            type Output = <$t as DivRounded<$t>>::Output;
669
670            #[inline(always)]
671            fn div_rounded(self, rhs: &$t, n_frac_digits: u8) -> Self::Output {
672                DivRounded::div_rounded(*self, *rhs, n_frac_digits)
673            }
674        }
675        )*
676    }
677}
678
679impl_div_rounded_int_and_int!();
680
681#[cfg(test)]
682#[allow(clippy::neg_multiply)]
683mod div_rounded_int_by_int_tests {
684    use super::*;
685
686    macro_rules! gen_div_rounded_int_by_int_tests {
687        ($func:ident, $i:expr, $j:expr, $r:expr,
688         $res_coeff:expr) => {
689            #[test]
690            fn $func() {
691                let i = $i;
692                let j = $j;
693                let r = i.div_rounded(j, $r);
694                assert_eq!(r.coefficient(), $res_coeff);
695                assert_eq!(r.n_frac_digits(), $r);
696                let r = (&i).div_rounded(j, $r);
697                assert_eq!(r.coefficient(), $res_coeff);
698                assert_eq!(r.n_frac_digits(), $r);
699                let r = i.div_rounded(&j, $r);
700                assert_eq!(r.coefficient(), $res_coeff);
701                assert_eq!(r.n_frac_digits(), $r);
702                let r = (&i).div_rounded(&j, $r);
703                assert_eq!(r.coefficient(), $res_coeff);
704                assert_eq!(r.n_frac_digits(), $r);
705            }
706        };
707    }
708
709    gen_div_rounded_int_by_int_tests!(test_u8, 44_u8, 3_u8, 5, 1466667);
710    gen_div_rounded_int_by_int_tests!(test_i8, -12_i8, -3_i8, 4, 40000);
711    gen_div_rounded_int_by_int_tests!(test_u16, 17_u16, 4_u16, 3, 4250);
712    gen_div_rounded_int_by_int_tests!(test_i16, -22, -13_i16, 7, 16923077);
713    gen_div_rounded_int_by_int_tests!(
714        test_u32,
715        u32::MAX,
716        10_u32,
717        0,
718        429496730
719    );
720    gen_div_rounded_int_by_int_tests!(test_i32, 12345_i32, -328_i32, 1, -376);
721    gen_div_rounded_int_by_int_tests!(
722        test_u64,
723        1_u64,
724        4294967295_u64,
725        32,
726        23283064370807973754315
727    );
728    gen_div_rounded_int_by_int_tests!(
729        test_i64,
730        i64::MIN,
731        u32::MAX as i64,
732        2,
733        -214748364850
734    );
735    gen_div_rounded_int_by_int_tests!(
736        test_i128,
737        987654321987654321_i128,
738        1234567890_i128,
739        1,
740        8000000081
741    );
742
743    #[test]
744    #[should_panic]
745    fn test_div_rounded_int_by_int_zero() {
746        let x = 17_u16;
747        let y = 0_u16;
748        let _z = x.div_rounded(y, 5);
749    }
750}