1use crate::cbig::CBig;
7use crate::repr::{combine_parts, CfpResult, Context};
8use core::ops::{Add, AddAssign, Sub, SubAssign};
9use dashu_float::round::Round;
10use dashu_int::Word;
11
12impl<R: Round> Context<R> {
13 pub fn add<const B: Word>(&self, z: &CBig<R, B>, w: &CBig<R, B>) -> CfpResult<R, B> {
18 let re = self.float().add(z.re(), w.re())?;
19 let im = self.float().add(z.im(), w.im())?;
20 Ok(combine_parts(re, im))
21 }
22
23 pub fn sub<const B: Word>(&self, z: &CBig<R, B>, w: &CBig<R, B>) -> CfpResult<R, B> {
28 let re = self.float().sub(z.re(), w.re())?;
29 let im = self.float().sub(z.im(), w.im())?;
30 Ok(combine_parts(re, im))
31 }
32}
33
34crate::helper_macros::impl_cbig_binop!(Add, add, AddAssign, add_assign);
36
37crate::helper_macros::impl_cbig_binop!(Sub, sub, SubAssign, sub_assign);
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use dashu_float::round::mode;
44
45 type C = CBig<mode::HalfAway, 10>;
46
47 #[test]
48 fn add_componentwise() {
49 let z = C::from_parts(3.into(), 4.into());
50 let w = C::from_parts(1.into(), 2.into());
51 let r = &z + &w;
52 assert_eq!(r.re().significand(), &4.into());
53 assert_eq!(r.im().significand(), &6.into());
54 }
55
56 #[test]
57 fn add_all_ref_val_combinations() {
58 let z = C::from_parts(1.into(), 2.into());
59 let w = C::from_parts(3.into(), 4.into());
60 assert_eq!((z.clone() + w.clone()).im().significand(), &6.into());
62 assert_eq!((z.clone() + &w).im().significand(), &6.into());
63 assert_eq!((&z + w.clone()).im().significand(), &6.into());
64 assert_eq!((&z + &w).im().significand(), &6.into());
65 }
66
67 #[test]
68 fn add_assign_val_and_ref() {
69 let z = C::from_parts(1.into(), 2.into());
70 let w = C::from_parts(3.into(), 4.into());
71
72 let mut acc = z.clone();
73 acc += w.clone();
74 assert_eq!(acc.re().significand(), &4.into());
75 assert_eq!(acc.im().significand(), &6.into());
76
77 let mut acc = z.clone();
78 acc += &w;
79 assert_eq!(acc.re().significand(), &4.into());
80 }
81
82 #[test]
83 fn sub_componentwise() {
84 let z = C::from_parts(3.into(), 4.into());
85 let w = C::from_parts(1.into(), 2.into());
86 let r = &z - &w;
87 assert_eq!(r.re().significand(), &2.into());
88 assert_eq!(r.im().significand(), &2.into());
89 }
90
91 #[test]
92 fn sub_all_ref_val_combinations() {
93 let z = C::from_parts(5.into(), 6.into());
94 let w = C::from_parts(2.into(), 1.into());
95 assert_eq!((z.clone() - w.clone()).re().significand(), &3.into());
96 assert_eq!((z.clone() - &w).re().significand(), &3.into());
97 assert_eq!((&z - w.clone()).re().significand(), &3.into());
98 assert_eq!((&z - &w).re().significand(), &3.into());
99 }
100
101 #[test]
102 fn z_minus_z_is_zero() {
103 let z = C::from_parts(7.into(), 9.into());
104 let r = &z - &z;
105 assert!(r.is_zero());
106 }
107
108 #[test]
109 fn sub_assign_val_and_ref() {
110 let z = C::from_parts(5.into(), 6.into());
111 let w = C::from_parts(2.into(), 1.into());
112
113 let mut acc = z.clone();
114 acc -= w.clone();
115 assert_eq!(acc.re().significand(), &3.into());
116 assert_eq!(acc.im().significand(), &5.into());
117
118 let mut acc = z.clone();
119 acc -= &w;
120 assert_eq!(acc.re().significand(), &3.into());
121 }
122}