Skip to main content

bigdecimal/arithmetic/
addition.rs

1//! addition routines
2//!
3
4use crate::*;
5use super::*;
6
7
8pub(crate) fn add_bigdecimals(
9    mut a: BigDecimal,
10    mut b: BigDecimal,
11) -> BigDecimal {
12    if b.is_zero() {
13        a.extend_scale_to(b.scale);
14        return a;
15    }
16
17    if a.is_zero() {
18        b.extend_scale_to(a.scale);
19        return b;
20    }
21
22    let (a, b) = match a.scale.cmp(&b.scale) {
23        Ordering::Equal => (a, b),
24        Ordering::Less => (a.take_and_scale(b.scale), b),
25        Ordering::Greater => (b.take_and_scale(a.scale), a),
26    };
27
28    add_aligned_bigdecimals(a, b)
29}
30
31fn add_aligned_bigdecimals(
32    mut a: BigDecimal,
33    mut b: BigDecimal,
34) -> BigDecimal {
35    if true {
    {
        match (&a.scale, &b.scale) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    let kind = ::core::panicking::AssertKind::Eq;
                    ::core::panicking::assert_failed(kind, &*left_val,
                        &*right_val, ::core::option::Option::None);
                }
            }
        }
    };
};debug_assert_eq!(a.scale, b.scale);
36    if a.int_val.bits() >= b.int_val.bits() {
37        a.int_val += b.int_val;
38        a
39    } else {
40        b.int_val += a.int_val;
41        b
42    }
43}
44
45
46pub(crate) fn add_bigdecimal_refs<'a, 'b, Lhs, Rhs>(
47    lhs: Lhs,
48    rhs: Rhs,
49    ctx: Option<&Context>,
50) -> BigDecimal
51where
52    Rhs: Into<BigDecimalRef<'a>>,
53    Lhs: Into<BigDecimalRef<'b>>,
54{
55    use stdlib::cmp::Ordering::*;
56
57    let lhs = lhs.into();
58    let rhs = rhs.into();
59    if rhs.is_zero() {
60        let scale_diff = rhs.scale.saturating_sub(lhs.scale).max(0).min(15);
61        return lhs.to_owned_with_scale(lhs.scale + scale_diff);
62    }
63    if lhs.is_zero() {
64        let scale_diff = lhs.scale.saturating_sub(rhs.scale).max(0).min(15);
65        return rhs.to_owned_with_scale(rhs.scale + scale_diff);
66    }
67
68    match lhs.scale.cmp(&rhs.scale) {
69        Equal => {
70            add_aligned_bigdecimal_ref_ref(lhs, rhs)
71        }
72        Greater => {
73            add_unaligned_bigdecimal_ref_ref(lhs, rhs, ctx)
74        }
75        Less => {
76            add_unaligned_bigdecimal_ref_ref(rhs, lhs, ctx)
77        }
78    }
79}
80
81
82pub(crate) fn addassign_bigdecimals(
83    lhs: &mut BigDecimal,
84    rhs: BigDecimal,
85) {
86    if rhs.is_zero() {
87        return;
88    }
89    if lhs.is_zero() {
90        *lhs = rhs;
91        return;
92    }
93    lhs.add_assign(rhs.to_ref());
94}
95
96
97pub(crate) fn addassign_bigdecimal_ref<'a, T: Into<BigDecimalRef<'a>>>(
98    lhs: &mut BigDecimal,
99    rhs: T,
100) {
101    // TODO: Replace to_owned() with efficient addition algorithm
102    let rhs = rhs.into().to_owned();
103    match lhs.scale.cmp(&rhs.scale) {
104        Ordering::Less => {
105            let scaled = lhs.with_scale(rhs.scale);
106            lhs.int_val = scaled.int_val + &rhs.int_val;
107            lhs.scale = rhs.scale;
108        }
109        Ordering::Greater => {
110            let scaled = rhs.with_scale(lhs.scale);
111            lhs.int_val += scaled.int_val;
112        }
113        Ordering::Equal => {
114            lhs.int_val += &rhs.int_val;
115        }
116    }
117}
118
119pub(crate) fn addassign_scaled_biguint(
120    lhs: &mut WithScale<BigUint>,
121    rhs: WithScale<&BigUint>,
122) {
123    use stdlib::cmp::Ordering::*;
124
125    if rhs.value.is_zero() {
126        return;
127    }
128    match diff(lhs.scale, rhs.scale) {
129        (Equal, _) => {
130            lhs.value += rhs.value;
131        }
132        (Less, d) => {
133            lhs.scale += d as i64;
134            multiply_by_ten_to_the_uint(&mut lhs.value, d);
135            lhs.value += rhs.value;
136        }
137        (Greater, d) => {
138            let mut tmp = rhs.value.clone();
139            multiply_by_ten_to_the_uint(&mut tmp, d);
140            lhs.value += tmp;
141        }
142    }
143}
144
145
146/// Add BigDecimal references which have the same scale (integer addition)
147fn add_aligned_bigdecimal_ref_ref(
148    lhs: BigDecimalRef, rhs: BigDecimalRef
149) -> BigDecimal {
150    if true {
    if !(!lhs.is_zero() && !rhs.is_zero()) {
        ::core::panicking::panic("assertion failed: !lhs.is_zero() && !rhs.is_zero()")
    };
};debug_assert!(!lhs.is_zero() && !rhs.is_zero());
151    if true {
    {
        match (&lhs.scale, &rhs.scale) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    let kind = ::core::panicking::AssertKind::Eq;
                    ::core::panicking::assert_failed(kind, &*left_val,
                        &*right_val, ::core::option::Option::None);
                }
            }
        }
    };
};debug_assert_eq!(lhs.scale, rhs.scale);
152
153    if lhs.digits.bits() >= rhs.digits.bits() {
154        lhs.to_owned() + rhs
155    } else {
156        rhs.to_owned() + lhs
157    }
158}
159
160fn add_unaligned_bigdecimal_ref_ref(
161    lhs: BigDecimalRef, rhs: BigDecimalRef, _ctx: Option<&Context>,
162) -> BigDecimal {
163    if true {
    if !(!lhs.is_zero() && !rhs.is_zero()) {
        ::core::panicking::panic("assertion failed: !lhs.is_zero() && !rhs.is_zero()")
    };
};debug_assert!(!lhs.is_zero() && !rhs.is_zero());
164    if true {
    if !(lhs.scale >= rhs.scale) {
        ::core::panicking::panic("assertion failed: lhs.scale >= rhs.scale")
    };
};debug_assert!(lhs.scale >= rhs.scale);
165
166    let scale_diff = (lhs.scale - rhs.scale) as u64;
167
168    let shifted_rhs_digits = rhs.digits * ten_to_the_uint(scale_diff);
169    let shifted_rhs_int = BigInt::from_biguint(rhs.sign, shifted_rhs_digits);
170    let shifted_rhs = BigDecimal::new(shifted_rhs_int, lhs.scale);
171
172    shifted_rhs + lhs
173}
174
175
176#[cfg(test)]
177mod test {
178    use super::*;
179
180    include!("addition.tests.rs");
181}