Skip to main content

relp_num/rational/big/ops/
add_sub.rs

1use std::ops::{Add, AddAssign, Sub, SubAssign};
2
3use crate::{Negateable, NonZero, Sign};
4use crate::rational::big::Big;
5use crate::rational::big::ops::building_blocks::{add_assign_fraction_non_zero, SignChange, sub_assign_fraction_non_zero};
6
7impl<const S: usize> Big<S> {
8    /// Subtract the magnitude of `rhs`, then fold the resulting sign change into `self.sign`.
9    ///
10    /// # Safety
11    ///
12    /// Neither value may be zero; the caller dispatches on the two signs to establish that.
13    unsafe fn sub_assign_update_sign(&mut self, rhs: &Self) {
14        // SAFETY: These four only read the last word of the value they are asked about; they are
15        // `unsafe` as a marker on the invariant they report on, and impose nothing on the caller.
16        unsafe {
17            debug_assert!(self.numerator.is_well_formed());
18            debug_assert!(self.denominator.is_well_formed());
19            debug_assert!(rhs.numerator.is_well_formed());
20            debug_assert!(rhs.denominator.is_well_formed());
21        }
22        debug_assert!(self.numerator.is_not_zero());
23        debug_assert!(self.denominator.is_not_zero());
24        debug_assert!(rhs.numerator.is_not_zero());
25        debug_assert!(rhs.denominator.is_not_zero());
26
27        // SAFETY: Both fractions are well formed, non zero by this function's contract, and in
28        // lowest terms because that is the invariant every `Big` upholds, which is what the
29        // subtraction needs. The two `inner_mut` calls hand out mutable access to the words behind
30        // that invariant; the subtraction restores it before returning, and the sign is brought
31        // back in line with the new magnitude just below.
32        let sign_change = unsafe {
33            sub_assign_fraction_non_zero(
34                self.numerator.inner_mut(),
35                self.denominator.inner_mut(),
36                &rhs.numerator,
37                &rhs.denominator,
38            )
39        };
40        match sign_change {
41            SignChange::None => {}
42            SignChange::Flip => self.sign.negate(),
43            SignChange::Zero => self.sign = Sign::Zero,
44        }
45    }
46}
47
48impl<const S: usize> Add for Big<S> {
49    type Output = Self;
50
51    #[inline]
52    fn add(mut self, rhs: Big<S>) -> Self::Output {
53        match (self.sign, rhs.sign) {
54            (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
55                // TODO(PERFORMANCE): Can the ownership of rhs be utilized?
56                unsafe {
57                    // SAFETY: All values are non zero
58                    add_assign_fraction_non_zero(
59                        self.numerator.inner_mut(),
60                        self.denominator.inner_mut(),
61                        &rhs.numerator,
62                        &rhs.denominator,
63                    )
64                }
65                self
66            },
67            (Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => {
68                // TODO(PERFORMANCE): Can the ownership of rhs be utilized?
69                unsafe {
70                    // SAFETY: All values are non zero
71                    self.sub_assign_update_sign(&rhs);
72                }
73                self
74            },
75            (_, Sign::Zero) => self,
76            (Sign::Zero, _) => rhs,
77        }
78    }
79}
80
81impl<const S: usize> Add<Big<S>> for &Big<S> {
82    type Output = Big<S>;
83
84    #[inline]
85    fn add(self, rhs: Big<S>) -> Self::Output {
86        Add::add(rhs, self)
87    }
88}
89
90impl<const S: usize> Add<&Big<S>> for Big<S> {
91    type Output = Self;
92
93    #[inline]
94    fn add(mut self, rhs: &Big<S>) -> Self::Output {
95        self += rhs;
96        self
97    }
98}
99
100impl<const S: usize> Add for &Big<S> {
101    type Output = Big<S>;
102
103    #[inline]
104    fn add(self, rhs: Self) -> Self::Output {
105        // TODO(PERFORMANCE): Which one should be cloned?
106        let x = self.clone();
107        x + rhs
108    }
109}
110
111impl<const S: usize> AddAssign for Big<S> {
112    #[inline]
113    fn add_assign(&mut self, rhs: Big<S>) {
114        // TODO(PERFORMANCE): Utilize ownership somehow?
115        AddAssign::add_assign(self, &rhs);
116    }
117}
118
119impl<const S: usize> AddAssign<&Big<S>> for Big<S> {
120    #[inline]
121    fn add_assign(&mut self, rhs: &Big<S>) {
122        match (self.sign, rhs.sign) {
123            (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
124                unsafe {
125                    // SAFETY: All values are non zero
126                    add_assign_fraction_non_zero(
127                        self.numerator.inner_mut(),
128                        self.denominator.inner_mut(),
129                        &rhs.numerator,
130                        &rhs.denominator,
131                    )
132                }
133            },
134            (Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => {
135                unsafe {
136                    // SAFETY: All values are non zero
137                    self.sub_assign_update_sign(rhs);
138                }
139            },
140            (_, Sign::Zero) => {},
141            (Sign::Zero, _) => *self = rhs.clone(),
142        }
143    }
144}
145
146impl<const S: usize> Sub for Big<S> {
147    type Output = Self;
148
149    #[inline]
150    fn sub(mut self, mut rhs: Big<S>) -> Self::Output {
151        match (self.sign, rhs.sign) {
152            (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
153                unsafe {
154                    // SAFETY: All values are non zero
155                    self.sub_assign_update_sign(&rhs);
156                }
157                self
158            },
159            (Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => {
160                unsafe {
161                    // SAFETY: All values are non zero
162                    add_assign_fraction_non_zero(
163                        self.numerator.inner_mut(),
164                        self.denominator.inner_mut(),
165                        &rhs.numerator,
166                        &rhs.denominator,
167                    );
168                }
169                self
170            },
171            (_, Sign::Zero) => self,
172            (Sign::Zero, _) => {
173                rhs.sign = !rhs.sign;
174                rhs
175            },
176        }
177    }
178}
179
180impl<const S: usize> Sub<&Big<S>> for Big<S> {
181    type Output = Self;
182
183    #[inline]
184    fn sub(mut self, rhs: &Big<S>) -> Self::Output {
185        SubAssign::sub_assign(&mut self, rhs);
186        self
187    }
188}
189
190impl<const S: usize> Sub<Big<S>> for &Big<S> {
191    type Output = Big<S>;
192
193    #[inline]
194    fn sub(self, rhs: Big<S>) -> Self::Output {
195        -Sub::sub(rhs, self)
196    }
197}
198
199impl<const S: usize> Sub for &Big<S> {
200    type Output = Big<S>;
201
202    #[inline]
203    fn sub(self, rhs: Self) -> Self::Output {
204        // TODO(PERFORMANCE): Which one should be cloned?
205        Sub::sub(self.clone(), rhs)
206    }
207}
208
209impl<const S: usize> SubAssign<Big<S>> for Big<S> {
210    // TODO(PERFORMANCE): Utilize ownership somehow?
211    #[inline]
212    fn sub_assign(&mut self, rhs: Big<S>) {
213        SubAssign::sub_assign(self, &rhs);
214    }
215}
216
217impl<const S: usize> SubAssign<&Big<S>> for Big<S> {
218    #[inline]
219    fn sub_assign(&mut self, rhs: &Big<S>) {
220        match (self.sign, rhs.sign) {
221            (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
222                unsafe {
223                    // SAFETY: All values are non zero
224                    self.sub_assign_update_sign(rhs);
225                }
226            },
227            (Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => unsafe {
228                add_assign_fraction_non_zero(
229                    self.numerator.inner_mut(),
230                    self.denominator.inner_mut(),
231                    &rhs.numerator,
232                    &rhs.denominator,
233                );
234            },
235            (_, Sign::Zero) => {},
236            (Sign::Zero, _) => {
237                *self = Self {
238                    sign: !rhs.sign,
239                    numerator: rhs.numerator.clone(),
240                    denominator: rhs.denominator.clone(),
241                };
242            },
243        }
244    }
245}
246
247#[cfg(test)]
248mod test {
249    use crate::RB;
250
251    #[test]
252    fn test_add() {
253        let mut x = RB!(3, 4);
254        x += RB!(-5, 6);
255        assert_eq!(x, RB!(3 * 6 - 5 * 4, 4 * 6));
256
257        let mut x = RB!(3, 4);
258        x += RB!(5, 6);
259        assert_eq!(x, RB!(3 * 6 + 5 * 4, 4 * 6));
260
261        let mut x = RB!(0);
262        x += &RB!(-5, 6);
263        assert_eq!(x, RB!(-5, 6));
264
265        let mut x = RB!(-5, 6);
266        x += RB!(0);
267        assert_eq!(x, RB!(-5, 6));
268    }
269
270    #[test]
271    fn test_sub() {
272        let mut x = RB!(3, 4);
273        x -= RB!(-5, 6);
274        assert_eq!(x, RB!(3 * 6 + 5 * 4, 4 * 6));
275
276        let mut x = RB!(3, 4);
277        x -= RB!(5, 6);
278        assert_eq!(x, RB!(3 * 6 - 5 * 4, 4 * 6));
279
280        let mut x = RB!(0);
281        x -= RB!(-5, 6);
282        assert_eq!(x, RB!(5, 6));
283
284        let mut x = RB!(-5, 6);
285        x -= &RB!(0);
286        assert_eq!(x, RB!(-5, 6));
287    }
288}