Skip to content

Commit 6eeb387

Browse files
committed
Fix and expand impl Sub<>
1 parent 71f0d63 commit 6eeb387

File tree

1 file changed

+174
-66
lines changed

1 file changed

+174
-66
lines changed

src/impl_ops_sub.rs

+174-66
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//!
2-
//! Multiplication operator trait implementation
2+
//! Subtraction operator trait implementation
33
//!
44
55
use crate::*;
@@ -19,111 +19,177 @@ impl Sub<BigDecimal> for BigDecimal {
1919
}
2020

2121
let mut lhs = self;
22-
let scale = cmp::max(lhs.scale, rhs.scale);
23-
2422
match lhs.scale.cmp(&rhs.scale) {
2523
Ordering::Equal => {
2624
lhs.int_val -= rhs.int_val;
2725
lhs
2826
}
29-
Ordering::Less => lhs.take_and_scale(scale) - rhs,
30-
Ordering::Greater => lhs - rhs.take_and_scale(scale),
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+
},
3134
}
3235
}
3336
}
3437

35-
impl<'a, T: Into<BigDecimalRef<'a>>> Sub<T> for BigDecimal {
38+
impl Sub<BigDecimal> for &'_ BigDecimal {
3639
type Output = BigDecimal;
3740

3841
#[inline]
42+
fn sub(self, rhs: BigDecimal) -> BigDecimal {
43+
self.to_ref() - rhs
44+
}
45+
}
46+
47+
impl 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+
56+
impl<'a, T: Into<BigDecimalRef<'a>>> Sub<T> for BigDecimal {
57+
type Output = BigDecimal;
58+
3959
fn sub(mut self, rhs: T) -> BigDecimal {
40-
let rhs = rhs.into();
41-
if rhs.is_zero() {
42-
return self
43-
}
60+
self.sub_assign(rhs);
61+
self
62+
}
63+
}
4464

45-
if self.is_zero() {
46-
self.int_val = BigInt::from_biguint(rhs.sign.neg(), rhs.digits.clone());
47-
self.scale = rhs.scale;
48-
return self
49-
}
65+
impl<'a, T: Into<BigDecimalRef<'a>>> Sub<T> for &'_ BigDecimal {
66+
type Output = BigDecimal;
5067

51-
let mut lhs = self;
52-
match lhs.scale.cmp(&rhs.scale) {
68+
fn sub(self, rhs: T) -> BigDecimal {
69+
let rhs = rhs.into();
70+
71+
match self.scale.cmp(&rhs.scale) {
5372
Ordering::Equal => {
54-
lhs.int_val -= BigInt::from_biguint(rhs.sign, rhs.digits.clone());
55-
lhs
73+
self.clone() - rhs
5674
}
5775
Ordering::Less => {
58-
lhs.take_and_scale(rhs.scale) - rhs.to_owned()
76+
self.with_scale(rhs.scale) - rhs
5977
}
6078
Ordering::Greater => {
61-
lhs - rhs.to_owned_with_scale(lhs.scale)
62-
},
79+
self - rhs.to_owned_with_scale(self.scale)
80+
}
6381
}
6482
}
6583
}
6684

67-
impl<'a> Sub<BigDecimal> for &'a BigDecimal {
85+
impl<'a, T: Into<BigDecimalRef<'a>>> Sub<T> for BigDecimalRef<'_> {
6886
type Output = BigDecimal;
6987

70-
#[inline]
71-
fn sub(self, rhs: BigDecimal) -> BigDecimal {
72-
-(rhs - self)
88+
fn sub(self, rhs: T) -> BigDecimal {
89+
let rhs = rhs.into();
90+
91+
match self.scale.cmp(&rhs.scale) {
92+
Ordering::Equal => self.clone() - rhs,
93+
Ordering::Less => self.to_owned_with_scale(rhs.scale) - rhs,
94+
Ordering::Greater => self - rhs.to_owned_with_scale(self.scale),
95+
}
7396
}
7497
}
7598

7699
impl Sub<BigInt> for BigDecimal {
77100
type Output = BigDecimal;
78101

102+
fn sub(mut self, rhs: BigInt) -> BigDecimal {
103+
self.sub_assign(rhs);
104+
self
105+
}
106+
}
107+
108+
109+
impl Sub<BigInt> for &'_ BigDecimal {
110+
type Output = BigDecimal;
111+
79112
#[inline]
80113
fn sub(self, rhs: BigInt) -> BigDecimal {
81-
if rhs.is_zero() {
82-
return self;
83-
}
114+
self.to_ref() - rhs
115+
}
116+
}
84117

85-
let mut lhs = self;
118+
impl Sub<BigInt> for BigDecimalRef<'_> {
119+
type Output = BigDecimal;
86120

87-
match lhs.scale.cmp(&0) {
88-
Ordering::Equal => {
89-
lhs.int_val -= rhs;
90-
lhs
91-
}
92-
Ordering::Greater => {
93-
lhs.int_val -= rhs * ten_to_the(lhs.scale as u64);
94-
lhs
95-
}
96-
Ordering::Less => lhs.take_and_scale(0) - rhs,
97-
}
121+
#[inline]
122+
fn sub(self, rhs: BigInt) -> BigDecimal {
123+
self - BigDecimal::from(rhs)
98124
}
99125
}
100126

101-
impl<'a> Sub<BigInt> for &'a BigDecimal {
127+
impl<'a> Sub<BigDecimal> for BigInt {
102128
type Output = BigDecimal;
103129

104130
#[inline]
105-
fn sub(self, rhs: BigInt) -> BigDecimal {
106-
BigDecimal::new(rhs, 0) - self
131+
fn sub(self, rhs: BigDecimal) -> BigDecimal {
132+
(rhs - self).neg()
107133
}
108134
}
109135

110-
impl<'a, 'b, T: Into<BigDecimalRef<'b>>> Sub<T> for &'a BigDecimal {
136+
impl<'a> Sub<BigDecimal> for &BigInt {
111137
type Output = BigDecimal;
112138

113139
#[inline]
114-
fn sub(self, rhs: T) -> BigDecimal {
115-
let rhs = rhs.into();
140+
fn sub(self, rhs: BigDecimal) -> BigDecimal {
141+
(rhs - self).neg()
142+
}
143+
}
144+
145+
impl<'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+
155+
impl<'a> Sub<BigDecimalRef<'a>> for &BigInt {
156+
type Output = BigDecimal;
116157

158+
#[inline]
159+
fn sub(self, rhs: BigDecimalRef<'a>) -> BigDecimal {
160+
(rhs - self).neg()
161+
}
162+
}
163+
164+
165+
impl 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+
}
117175
match self.scale.cmp(&rhs.scale) {
118-
Ordering::Equal => self.clone() - rhs,
119-
Ordering::Less => self.with_scale(rhs.scale) - rhs,
120-
Ordering::Greater => self - rhs.to_owned_with_scale(self.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+
}
121189
}
122190
}
123191
}
124192

125-
forward_val_assignop!(impl SubAssign for BigDecimal, sub_assign);
126-
127193
impl<'rhs, T: Into<BigDecimalRef<'rhs>>> SubAssign<T> for BigDecimal {
128194
#[inline]
129195
fn sub_assign(&mut self, rhs: T) {
@@ -169,27 +235,68 @@ mod test {
169235
($name:ident: $a:literal - $b:literal => $c:literal ) => {
170236
#[test]
171237
fn $name() {
172-
let mut a: BigDecimal = $a.parse().unwrap();
238+
let a: BigDecimal = $a.parse().unwrap();
173239
let b: BigDecimal = $b.parse().unwrap();
174240
let c: BigDecimal = $c.parse().unwrap();
175241

176-
assert_eq!(a.clone() - b.clone(), c);
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);
177247

178-
assert_eq!(a.clone() - &b, c);
179-
assert_eq!(&a - b.clone(), c);
180-
assert_eq!(&a - &b, c);
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());
181251

182-
a -= b;
183-
assert_eq!(a, c);
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());
184286
}
185287
};
186288
}
187289

188290
impl_case!(case_1234en2_1234en3: "12.34" - "1.234" => "11.106");
189291
impl_case!(case_1234en2_n1234en3: "12.34" - "-1.234" => "13.574");
190292
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");
191295
impl_case!(case_85616001e4_0: "85616001e4" - "0" => "85616001e4");
192296
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");
193300

194301
#[cfg(property_tests)]
195302
mod prop {
@@ -203,21 +310,22 @@ mod test {
203310
// ignore non-normal numbers
204311
prop_assume!(f.is_normal());
205312
prop_assume!(g.is_normal());
313+
prop_assume!((f.log10() - g.log10()).abs() < 100_000);
206314

207315
let a = BigDecimal::from_f32(f).unwrap();
208316
let b = BigDecimal::from_f32(g).unwrap();
209-
let own_plus_ref = a.clone() + &b;
210-
let ref_plus_own = &a + b.clone();
317+
let own_minus_ref = a.clone() - &b;
318+
let ref_minus_own = &a - b.clone();
211319

212320
let mut c = a.clone();
213-
c += &b;
321+
c -= &b;
214322

215323
let mut d = a.clone();
216-
d += b;
324+
d -= b;
217325

218-
prop_assert_eq!(&own_plus_ref, &ref_plus_own);
219-
prop_assert_eq!(&c, &ref_plus_own);
220-
prop_assert_eq!(&d, &ref_plus_own);
326+
prop_assert_eq!(&own_minus_ref, &ref_minus_own);
327+
prop_assert_eq!(&c, &ref_minus_own);
328+
prop_assert_eq!(&d, &ref_minus_own);
221329
}
222330

223331
#[test]

0 commit comments

Comments
 (0)