Skip to main content

bigdecimal/arithmetic/
division.rs

1//! Routines for implementing division
2//!
3
4use crate::*;
5
6pub(crate) fn scaled_uint_division_into<'a, N, D>(
7    dest: &mut WithScale<BigUint>,
8    num: N,
9    den: D,
10    max_precision_bits: u64,
11)
12where
13    N: Into<WithScale<&'a BigUint>>,
14    D: Into<WithScale<&'a BigUint>>,
15{
16    impl_scaled_uint_division_into(dest, num.into(), den.into(), max_precision_bits);
17}
18
19/// implement `dest = num / den`, limiting the precision to given number of bits
20pub(crate) fn impl_scaled_uint_division_into(
21    dest: &mut WithScale<BigUint>,
22    num: WithScale<&BigUint>,
23    den: WithScale<&BigUint>,
24    max_precision_bits: u64,
25) {
26    if true {
    if !!den.value.is_zero() {
        ::core::panicking::panic("assertion failed: !den.value.is_zero()")
    };
};debug_assert!(!den.value.is_zero());
27
28    if num.value.is_zero() {
29        dest.value = num.value.clone();
30        dest.scale = num.scale - den.scale;
31        return;
32    }
33
34    if den.value.is_one() && den.scale == 0 {
35        return;
36    }
37
38    let WithScale { value: num, scale: num_scale } = num;
39    let WithScale { value: den, scale: den_scale } = den;
40
41    // populate dest with scaled numerator (larger than denominator)
42    match den.bits().checked_sub(num.bits()) {
43        None => {
44            dest.scale = num_scale - den_scale;
45            dest.value = num.clone();
46        }
47        Some(0) => {
48            dest.scale = num_scale - den_scale + 1;
49            dest.value = num * 10u8;
50        }
51        Some(diff) => {
52            let digit_count = bit_to_digit_count(diff);
53            dest.scale = num_scale - den_scale + digit_count as i64;
54            dest.value = BigUint::from(10u8).pow(digit_count);
55            dest.value *= num;
56        }
57    }
58
59    let (quotient, mut remainder) = dest.value.div_rem(den);
60
61    dest.value = quotient;
62
63    // precision of results in bits
64    let mut precision_bits = dest.bits();
65
66    // increase precision 'step-scale' digits at a time
67    let step_scale = 1i64;
68    let step_factor = 10u64.pow(step_scale as u32);
69
70    // shift remainder by 2 decimal;
71    // quotient will be at most 'step-scale' digit upon next div_rem
72    remainder *= step_factor;
73
74    while !remainder.is_zero() && precision_bits < max_precision_bits {
75        let (q, r) = remainder.div_rem(den);
76        dest.scale += step_scale;
77        dest.value *= step_factor;
78        dest.value += q;
79        precision_bits = dest.bits();
80        remainder = r * step_factor;
81    }
82
83    let excess_u64_count = precision_bits.saturating_sub(max_precision_bits) / 64;
84
85    // Trim some excess precision from the division
86    for _ in 1..excess_u64_count {
87        dest.value /= 1_0000000000000000000u64;
88        dest.scale -= 19;
89    }
90}