Skip to content

Commit 463e55c

Browse files
committed
Merge impl reorganization into trunk
2 parents e4eca0b + 8765b17 commit 463e55c

File tree

7 files changed

+1141
-941
lines changed

7 files changed

+1141
-941
lines changed

src/impl_ops.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,6 @@
11
//! Implement math operations: Add,Sub, etc
22
3-
use crate::{
4-
BigDecimal,
5-
BigDecimalRef,
6-
};
7-
use crate::stdlib::ops::{
8-
Add, AddAssign,
9-
Sub, SubAssign,
10-
Mul, MulAssign,
11-
Div, DivAssign,
12-
Neg,
13-
};
14-
15-
16-
use crate::stdlib::convert::TryFrom;
17-
18-
use num_traits::{Zero, One};
3+
use crate::*;
194

205

216
macro_rules! impl_add_for_primitive {

src/impl_ops_add.rs

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
//! Addition operator trait implementation
2+
//!
3+
4+
use super::*;
5+
6+
7+
impl Add<BigDecimal> for BigDecimal {
8+
type Output = BigDecimal;
9+
10+
#[inline]
11+
fn add(self, rhs: BigDecimal) -> BigDecimal {
12+
let mut lhs = self;
13+
14+
match lhs.scale.cmp(&rhs.scale) {
15+
Ordering::Equal => {
16+
lhs.int_val += rhs.int_val;
17+
lhs
18+
}
19+
Ordering::Less => lhs.take_and_scale(rhs.scale) + rhs,
20+
Ordering::Greater => rhs.take_and_scale(lhs.scale) + lhs,
21+
}
22+
}
23+
}
24+
25+
impl<'a> Add<&'a BigDecimal> for BigDecimal {
26+
type Output = BigDecimal;
27+
28+
#[inline]
29+
fn add(self, rhs: &'a BigDecimal) -> BigDecimal {
30+
let mut lhs = self;
31+
32+
match lhs.scale.cmp(&rhs.scale) {
33+
Ordering::Equal => {
34+
lhs.int_val += &rhs.int_val;
35+
lhs
36+
}
37+
Ordering::Less => lhs.take_and_scale(rhs.scale) + rhs,
38+
Ordering::Greater => rhs.with_scale(lhs.scale) + lhs,
39+
}
40+
}
41+
}
42+
43+
impl<'a> Add<BigDecimal> for &'a BigDecimal {
44+
type Output = BigDecimal;
45+
46+
#[inline]
47+
fn add(self, rhs: BigDecimal) -> BigDecimal {
48+
rhs + self
49+
}
50+
}
51+
52+
impl<'a, 'b> Add<&'b BigDecimal> for &'a BigDecimal {
53+
type Output = BigDecimal;
54+
55+
#[inline]
56+
fn add(self, rhs: &BigDecimal) -> BigDecimal {
57+
let lhs = self;
58+
match self.scale.cmp(&rhs.scale) {
59+
Ordering::Less => lhs.with_scale(rhs.scale) + rhs,
60+
Ordering::Greater => rhs.with_scale(lhs.scale) + lhs,
61+
Ordering::Equal => BigDecimal::new(lhs.int_val.clone() + &rhs.int_val, lhs.scale),
62+
}
63+
}
64+
}
65+
66+
impl Add<BigInt> for BigDecimal {
67+
type Output = BigDecimal;
68+
69+
#[inline]
70+
fn add(self, rhs: BigInt) -> BigDecimal {
71+
let mut lhs = self;
72+
73+
match lhs.scale.cmp(&0) {
74+
Ordering::Equal => {
75+
lhs.int_val += rhs;
76+
lhs
77+
}
78+
Ordering::Greater => {
79+
lhs.int_val += rhs * ten_to_the(lhs.scale as u64);
80+
lhs
81+
}
82+
Ordering::Less => lhs.take_and_scale(0) + rhs,
83+
}
84+
}
85+
}
86+
87+
impl<'a> Add<&'a BigInt> for BigDecimal {
88+
type Output = BigDecimal;
89+
90+
#[inline]
91+
fn add(self, rhs: &BigInt) -> BigDecimal {
92+
let mut lhs = self;
93+
94+
match lhs.scale.cmp(&0) {
95+
Ordering::Equal => {
96+
lhs.int_val += rhs;
97+
lhs
98+
}
99+
Ordering::Greater => {
100+
lhs.int_val += rhs * ten_to_the(lhs.scale as u64);
101+
lhs
102+
}
103+
Ordering::Less => lhs.take_and_scale(0) + rhs,
104+
}
105+
}
106+
}
107+
108+
impl<'a> Add<BigInt> for &'a BigDecimal {
109+
type Output = BigDecimal;
110+
111+
#[inline]
112+
fn add(self, rhs: BigInt) -> BigDecimal {
113+
BigDecimal::new(rhs, 0) + self
114+
}
115+
}
116+
117+
impl<'a, 'b> Add<&'a BigInt> for &'b BigDecimal {
118+
type Output = BigDecimal;
119+
120+
#[inline]
121+
fn add(self, rhs: &BigInt) -> BigDecimal {
122+
self.with_scale(0) + rhs
123+
}
124+
}
125+
126+
forward_val_assignop!(impl AddAssign for BigDecimal, add_assign);
127+
128+
impl<'a> AddAssign<&'a BigDecimal> for BigDecimal {
129+
#[inline]
130+
fn add_assign(&mut self, rhs: &BigDecimal) {
131+
match self.scale.cmp(&rhs.scale) {
132+
Ordering::Less => {
133+
let scaled = self.with_scale(rhs.scale);
134+
self.int_val = scaled.int_val + &rhs.int_val;
135+
self.scale = rhs.scale;
136+
}
137+
Ordering::Greater => {
138+
let scaled = rhs.with_scale(self.scale);
139+
self.int_val += scaled.int_val;
140+
}
141+
Ordering::Equal => {
142+
self.int_val += &rhs.int_val;
143+
}
144+
}
145+
}
146+
}
147+
148+
impl AddAssign<BigInt> for BigDecimal {
149+
#[inline]
150+
fn add_assign(&mut self, rhs: BigInt) {
151+
*self += BigDecimal::new(rhs, 0)
152+
}
153+
}
154+
155+
impl<'a> AddAssign<&'a BigInt> for BigDecimal {
156+
#[inline]
157+
fn add_assign(&mut self, rhs: &BigInt) {
158+
match self.scale.cmp(&0) {
159+
Ordering::Equal => self.int_val += rhs,
160+
Ordering::Greater => self.int_val += rhs * ten_to_the(self.scale as u64),
161+
Ordering::Less => {
162+
// *self += BigDecimal::new(rhs, 0)
163+
self.int_val *= ten_to_the((-self.scale) as u64);
164+
self.int_val += rhs;
165+
self.scale = 0;
166+
}
167+
}
168+
}
169+
}
170+
171+
172+
#[cfg(test)]
173+
mod test {
174+
use super::*;
175+
use paste::paste;
176+
177+
macro_rules! impl_case {
178+
($name:ident: $a:literal + $b:literal => $c:literal ) => {
179+
#[test]
180+
fn $name() {
181+
let mut a: BigDecimal = $a.parse().unwrap();
182+
let b: BigDecimal = $b.parse().unwrap();
183+
let c: BigDecimal = $c.parse().unwrap();
184+
185+
assert_eq!(a.clone() + b.clone(), c);
186+
187+
assert_eq!(a.clone() + &b, c);
188+
assert_eq!(&a + b.clone(), c);
189+
assert_eq!(&a + &b, c);
190+
191+
a += b;
192+
assert_eq!(a, c);
193+
}
194+
};
195+
}
196+
197+
impl_case!(case_1234en2_1234en3: "12.34" + "1.234" => "13.574");
198+
impl_case!(case_1234en2_n1234en3: "12.34" + "-1.234" => "11.106");
199+
impl_case!(case_1234en2_n1234en2: "12.34" + "-12.34" => "0");
200+
impl_case!(case_1234e6_1234en6: "1234e6" + "1234e-6" => "1234000000.001234");
201+
impl_case!(case_1234en6_1234e6: "1234e6" + "1234e-6" => "1234000000.001234");
202+
impl_case!(case_18446744073709551616_1: "18446744073709551616.0" + "1" => "18446744073709551617");
203+
impl_case!(case_184467440737e3380_1: "184467440737e3380" + "0" => "184467440737e3380");
204+
205+
206+
#[cfg(property_tests)]
207+
mod prop {
208+
use super::*;
209+
use proptest::*;
210+
use num_traits::FromPrimitive;
211+
212+
proptest! {
213+
#[test]
214+
fn add_refs_and_owners(f: f32, g: f32) {
215+
// ignore non-normal numbers
216+
prop_assume!(f.is_normal());
217+
prop_assume!(g.is_normal());
218+
219+
let a = BigDecimal::from_f32(f).unwrap();
220+
let b = BigDecimal::from_f32(g).unwrap();
221+
let own_plus_ref = a.clone() + &b;
222+
let ref_plus_own = &a + b.clone();
223+
224+
let mut c = a.clone();
225+
c += &b;
226+
227+
let mut d = a.clone();
228+
d += b;
229+
230+
prop_assert_eq!(&own_plus_ref, &ref_plus_own);
231+
prop_assert_eq!(&c, &ref_plus_own);
232+
prop_assert_eq!(&d, &ref_plus_own);
233+
}
234+
235+
#[test]
236+
fn addition_is_communative(f: f32, g: f32) {
237+
// ignore non-normal numbers
238+
prop_assume!(f.is_normal());
239+
prop_assume!(g.is_normal());
240+
241+
let a = BigDecimal::from_f32(f).unwrap();
242+
let b = BigDecimal::from_f32(g).unwrap();
243+
let a_plus_b = &a + &b;
244+
let b_plus_a = &b + &a;
245+
246+
prop_assert_eq!(a_plus_b, b_plus_a)
247+
}
248+
249+
#[test]
250+
fn addition_is_associative(f: f32, g: f32, h: f32) {
251+
// ignore non-normal numbers
252+
prop_assume!(f.is_normal());
253+
prop_assume!(g.is_normal());
254+
prop_assume!(h.is_normal());
255+
256+
let a = BigDecimal::from_f32(f).unwrap();
257+
let b = BigDecimal::from_f32(g).unwrap();
258+
let c = BigDecimal::from_f32(h).unwrap();
259+
260+
let ab = &a + &b;
261+
let ab_c = ab + &c;
262+
263+
let bc = &b + &c;
264+
let a_bc = a + bc;
265+
266+
prop_assert_eq!(ab_c, a_bc)
267+
}
268+
}
269+
}
270+
}

0 commit comments

Comments
 (0)