bigdecimal/
impl_ops_sub.rs

1//!
2//! Subtraction operator trait implementation
3//!
4
5use crate::*;
6
7
8impl Sub<BigDecimal> for BigDecimal {
9    type Output = BigDecimal;
10
11    #[inline]
12    fn sub(self, rhs: BigDecimal) -> BigDecimal {
13        if rhs.is_zero() {
14            return self;
15        }
16
17        if self.is_zero() {
18            return rhs.neg();
19        }
20
21        let mut lhs = self;
22        match lhs.scale.cmp(&rhs.scale) {
23            Ordering::Equal => {
24                lhs.int_val -= rhs.int_val;
25                lhs
26            }
27            Ordering::Less => {
28                lhs.take_and_scale(rhs.scale) - rhs
29            }
30            Ordering::Greater => {
31                let rhs = rhs.take_and_scale(lhs.scale);
32                lhs - rhs
33            },
34        }
35    }
36}
37
38impl Sub<BigDecimal> for &'_ BigDecimal {
39    type Output = BigDecimal;
40
41    #[inline]
42    fn sub(self, rhs: BigDecimal) -> BigDecimal {
43        self.to_ref() - rhs
44    }
45}
46
47impl Sub<BigDecimal> for BigDecimalRef<'_> {
48    type Output = BigDecimal;
49
50    #[inline]
51    fn sub(self, rhs: BigDecimal) -> BigDecimal {
52        (rhs - self).neg()
53    }
54}
55
56impl<'a, T: Into<BigDecimalRef<'a>>> Sub<T> for BigDecimal {
57    type Output = BigDecimal;
58
59    fn sub(mut self, rhs: T) -> BigDecimal {
60        self.sub_assign(rhs);
61        self
62    }
63}
64
65impl<'a, T: Into<BigDecimalRef<'a>>> Sub<T> for &'_ BigDecimal {
66    type Output = BigDecimal;
67
68    fn sub(self, rhs: T) -> BigDecimal {
69        let rhs = rhs.into();
70
71        match self.scale.cmp(&rhs.scale) {
72            Ordering::Equal => {
73                self.clone() - rhs
74            }
75            Ordering::Less => {
76                self.with_scale(rhs.scale) - rhs
77            }
78            Ordering::Greater => {
79                self - rhs.to_owned_with_scale(self.scale)
80            }
81        }
82    }
83}
84
85impl<'a, T: Into<BigDecimalRef<'a>>> Sub<T> for BigDecimalRef<'_> {
86    type Output = BigDecimal;
87
88    fn sub(self, rhs: T) -> BigDecimal {
89        let rhs = rhs.into();
90
91        match self.scale.cmp(&rhs.scale) {
92            Ordering::Equal => self.to_owned() - rhs,
93            Ordering::Less => self.to_owned_with_scale(rhs.scale) - rhs,
94            Ordering::Greater => self - rhs.to_owned_with_scale(self.scale),
95        }
96    }
97}
98
99impl Sub<BigInt> for BigDecimal {
100    type Output = BigDecimal;
101
102    fn sub(mut self, rhs: BigInt) -> BigDecimal {
103        self.sub_assign(rhs);
104        self
105    }
106}
107
108
109impl Sub<BigInt> for &'_ BigDecimal {
110    type Output = BigDecimal;
111
112    #[inline]
113    fn sub(self, rhs: BigInt) -> BigDecimal {
114        self.to_ref() - rhs
115    }
116}
117
118impl Sub<BigInt> for BigDecimalRef<'_> {
119    type Output = BigDecimal;
120
121    #[inline]
122    fn sub(self, rhs: BigInt) -> BigDecimal {
123        self - BigDecimal::from(rhs)
124    }
125}
126
127impl Sub<BigDecimal> for BigInt {
128    type Output = BigDecimal;
129
130    #[inline]
131    fn sub(self, rhs: BigDecimal) -> BigDecimal {
132        (rhs - self).neg()
133    }
134}
135
136impl Sub<BigDecimal> for &BigInt {
137    type Output = BigDecimal;
138
139    #[inline]
140    fn sub(self, rhs: BigDecimal) -> BigDecimal {
141        (rhs - self).neg()
142    }
143}
144
145impl<'a> Sub<BigDecimalRef<'a>> for BigInt {
146    type Output = BigDecimal;
147
148    #[inline]
149    fn sub(self, rhs: BigDecimalRef<'a>) -> BigDecimal {
150        (rhs - &self).neg()
151    }
152}
153
154
155impl<'a> Sub<BigDecimalRef<'a>> for &BigInt {
156    type Output = BigDecimal;
157
158    #[inline]
159    fn sub(self, rhs: BigDecimalRef<'a>) -> BigDecimal {
160        (rhs - self).neg()
161    }
162}
163
164
165impl SubAssign<BigDecimal> for BigDecimal {
166    #[inline]
167    fn sub_assign(&mut self, rhs: BigDecimal) {
168        if rhs.is_zero() {
169            return;
170        }
171        if self.is_zero() {
172            *self = rhs.neg();
173            return;
174        }
175        match self.scale.cmp(&rhs.scale) {
176            Ordering::Equal => {
177                self.int_val -= rhs.int_val;
178            }
179            Ordering::Less => {
180                self.int_val *= ten_to_the((rhs.scale - self.scale) as u64);
181                self.int_val -= rhs.int_val;
182                self.scale = rhs.scale;
183            }
184            Ordering::Greater => {
185                let mut rhs_int_val = rhs.int_val;
186                rhs_int_val *= ten_to_the((self.scale - rhs.scale) as u64);
187                self.int_val -= rhs_int_val;
188            }
189        }
190    }
191}
192
193impl<'rhs, T: Into<BigDecimalRef<'rhs>>> SubAssign<T> for BigDecimal {
194    #[inline]
195    fn sub_assign(&mut self, rhs: T) {
196        let rhs = rhs.into();
197        if rhs.is_zero() {
198            return;
199        }
200        if self.is_zero() {
201            *self = rhs.neg().to_owned();
202            return;
203        }
204
205        match self.scale.cmp(&rhs.scale) {
206            Ordering::Equal => {
207                self.int_val -= rhs.to_owned().int_val;
208            }
209            Ordering::Less => {
210                self.int_val *= ten_to_the((rhs.scale - self.scale) as u64);
211                self.int_val -= rhs.to_owned().int_val;
212                self.scale = rhs.scale;
213            }
214            Ordering::Greater => {
215                *self -= rhs.to_owned_with_scale(self.scale);
216            }
217        }
218    }
219}
220
221impl SubAssign<BigInt> for BigDecimal {
222    #[inline(always)]
223    fn sub_assign(&mut self, rhs: BigInt) {
224        *self -= BigDecimal::new(rhs, 0)
225    }
226}
227
228
229#[cfg(test)]
230mod test {
231    use super::*;
232    use paste::paste;
233
234    macro_rules! impl_case {
235        ($name:ident: $a:literal - $b:literal => $c:literal ) => {
236            #[test]
237            fn $name() {
238                let a: BigDecimal = $a.parse().unwrap();
239                let b: BigDecimal = $b.parse().unwrap();
240                let c: BigDecimal = $c.parse().unwrap();
241
242                assert_eq!(c, a.clone() - b.clone());
243
244                assert_eq!(c, a.clone() - &b);
245                assert_eq!(c, &a - b.clone());
246                assert_eq!(c, &a - &b);
247
248                assert_eq!(c, a.to_ref() - &b);
249                assert_eq!(c, &a - b.to_ref());
250                assert_eq!(c, a.to_ref() - b.to_ref());
251
252                let mut n = a.clone();
253                n -= b.to_ref();
254                assert_eq!(n, c);
255
256                let mut n = a.clone();
257                n -= &b;
258                assert_eq!(n, c);
259
260                let mut n = a.clone();
261                n -= b.clone();
262                assert_eq!(n, c);
263
264                let mut n = a.clone();
265                (&mut n).sub_assign(b.clone());
266                assert_eq!(n, c);
267            }
268        };
269        ($name:ident: $a:literal - (int) $b:literal => $c:literal ) => {
270            #[test]
271            fn $name() {
272                let a: BigDecimal = $a.parse().unwrap();
273                let b: BigInt = $b.parse().unwrap();
274                let expected: BigDecimal = $c.parse().unwrap();
275
276                assert_eq!(expected, a.clone() - b.clone());
277                assert_eq!(expected, a.clone() - &b);
278                assert_eq!(expected, &a - &b);
279                assert_eq!(expected, &a - b.clone());
280                assert_eq!(expected, a.to_ref() - &b);
281
282                let expected_neg = expected.clone().neg();
283                assert_eq!(expected_neg, b.clone() - a.clone());
284                assert_eq!(expected_neg, &b - a.to_ref());
285                assert_eq!(expected_neg, &b - a.clone());
286            }
287        };
288    }
289
290    impl_case!(case_1234en2_1234en3: "12.34" - "1.234" => "11.106");
291    impl_case!(case_1234en2_n1234en3: "12.34" - "-1.234" => "13.574");
292    impl_case!(case_1234e6_1234en6: "1234e6" - "1234e-6" => "1233999999.998766");
293    impl_case!(case_1234en6_1234e6: "1234e-6" - "1234e6" => "-1233999999.998766");
294    impl_case!(case_712911676en6_4856259269250829: "712911676e-6" - "4856259269250829" => "-4856259269250116.088324");
295    impl_case!(case_85616001e4_0: "85616001e4" - "0" => "85616001e4");
296    impl_case!(case_0_520707672en5: "0" - "5207.07672" => "-520707672e-5");
297    impl_case!(case_99291289e5_int0: "99291289e5" - (int)"0" => "99291289e5");
298    impl_case!(case_7051277471570131en16_int1: "0.7051277471570131" - (int)"1" => "-0.2948722528429869");
299    impl_case!(case_4068603022763836en8_intneg10: "40686030.22763836" - (int)"-10" => "40686040.22763836");
300
301    #[cfg(property_tests)]
302    mod prop {
303        use super::*;
304        use proptest::*;
305        use num_traits::FromPrimitive;
306
307        proptest! {
308            #[test]
309            fn sub_refs_and_owners(f: f32, g: f32) {
310                // ignore non-normal numbers
311                prop_assume!(f.is_normal());
312                prop_assume!(g.is_normal());
313
314                let a = BigDecimal::from_f32(f).unwrap();
315                let b = BigDecimal::from_f32(g).unwrap();
316                let own_minus_ref = a.clone() - &b;
317                let ref_minus_own = &a - b.clone();
318
319                let mut c = a.clone();
320                c -= &b;
321
322                let mut d = a.clone();
323                d -= b;
324
325                prop_assert_eq!(&own_minus_ref, &ref_minus_own);
326                prop_assert_eq!(&c, &ref_minus_own);
327                prop_assert_eq!(&d, &ref_minus_own);
328            }
329
330            #[test]
331            fn subtraction_is_anticommunative(f: f32, g: f32) {
332                // ignore non-normal numbers
333                prop_assume!(f.is_normal());
334                prop_assume!(g.is_normal());
335
336                let a = BigDecimal::from_f32(f).unwrap();
337                let b = BigDecimal::from_f32(g).unwrap();
338                let a_minus_b = &a - &b;
339                let b_minus_a = &b - &a;
340
341                prop_assert_eq!(a_minus_b, -b_minus_a)
342            }
343        }
344    }
345}