malachite_q/arithmetic/
sub.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5//      Copyright © 1991, 1994-1997, 2000, 2001, 2004, 2005 Free Software Foundation, Inc.
6//
7// This file is part of Malachite.
8//
9// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
10// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
11// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
12
13use crate::Rational;
14use core::ops::{Sub, SubAssign};
15use malachite_base::num::arithmetic::traits::{
16    DivExact, DivExactAssign, Gcd, GcdAssign, NegAssign, UnsignedAbs,
17};
18use malachite_nz::integer::Integer;
19
20impl Sub<Self> for Rational {
21    type Output = Self;
22
23    /// Subtracts a [`Rational`] by another [`Rational`], taking both by value.
24    ///
25    /// $$
26    /// f(x, y) = x - y.
27    /// $$
28    ///
29    /// # Worst-case complexity
30    /// $T(n) = O(n (\log n)^2 \log\log n)$
31    ///
32    /// $M(n) = O(n \log n)$
33    ///
34    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
35    /// other.significant_bits())`.
36    ///
37    /// # Examples
38    /// ```
39    /// use malachite_base::num::basic::traits::OneHalf;
40    /// use malachite_q::Rational;
41    ///
42    /// assert_eq!(Rational::ONE_HALF - Rational::ONE_HALF, 0);
43    /// assert_eq!(
44    ///     (Rational::from_signeds(22, 7) - Rational::from_signeds(99, 100)).to_string(),
45    ///     "1507/700"
46    /// );
47    /// ```
48    fn sub(self, other: Self) -> Self {
49        if self == 0u32 {
50            return -other;
51        } else if other == 0u32 {
52            return self;
53        }
54        let mut gcd = (&self.denominator).gcd(&other.denominator);
55        if gcd == 1u32 {
56            let diff_n = Integer::from_sign_and_abs(self.sign, self.numerator * &other.denominator)
57                - Integer::from_sign_and_abs(other.sign, other.numerator * &self.denominator);
58            let diff_d = self.denominator * other.denominator;
59            Self {
60                sign: diff_n >= 0,
61                numerator: diff_n.unsigned_abs(),
62                denominator: diff_d,
63            }
64        } else {
65            let reduced_self_d = (self.denominator).div_exact(&gcd);
66            let diff_n =
67                Integer::from_sign_and_abs(
68                    self.sign,
69                    self.numerator * (&other.denominator).div_exact(&gcd),
70                ) - Integer::from_sign_and_abs(other.sign, other.numerator * &reduced_self_d);
71            gcd.gcd_assign(diff_n.unsigned_abs_ref());
72            if gcd == 1u32 {
73                Self {
74                    sign: diff_n >= 0,
75                    numerator: diff_n.unsigned_abs(),
76                    denominator: other.denominator * reduced_self_d,
77                }
78            } else {
79                Self {
80                    sign: diff_n >= 0,
81                    numerator: diff_n.unsigned_abs().div_exact(&gcd),
82                    denominator: (other.denominator).div_exact(gcd) * reduced_self_d,
83                }
84            }
85        }
86    }
87}
88
89impl Sub<&Self> for Rational {
90    type Output = Self;
91
92    /// Subtracts a [`Rational`] by another [`Rational`], taking the first by value and the second
93    /// by reference.
94    ///
95    /// $$
96    /// f(x, y) = x - y.
97    /// $$
98    ///
99    /// # Worst-case complexity
100    /// $T(n) = O(n (\log n)^2 \log\log n)$
101    ///
102    /// $M(n) = O(n \log n)$
103    ///
104    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
105    /// other.significant_bits())`.
106    ///
107    /// # Examples
108    /// ```
109    /// use malachite_base::num::basic::traits::OneHalf;
110    /// use malachite_q::Rational;
111    ///
112    /// assert_eq!(Rational::ONE_HALF - &Rational::ONE_HALF, 0);
113    /// assert_eq!(
114    ///     (Rational::from_signeds(22, 7) - &Rational::from_signeds(99, 100)).to_string(),
115    ///     "1507/700"
116    /// );
117    /// ```
118    #[inline]
119    fn sub(self, other: &Self) -> Self {
120        -(other - self)
121    }
122}
123
124impl Sub<Rational> for &Rational {
125    type Output = Rational;
126
127    /// Subtracts a [`Rational`] by another [`Rational`], taking the first by reference and the
128    /// second by value.
129    ///
130    /// $$
131    /// f(x, y) = x - y.
132    /// $$
133    ///
134    /// # Worst-case complexity
135    /// $T(n) = O(n (\log n)^2 \log\log n)$
136    ///
137    /// $M(n) = O(n \log n)$
138    ///
139    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
140    /// other.significant_bits())`.
141    ///
142    /// # Examples
143    /// ```
144    /// use malachite_base::num::basic::traits::OneHalf;
145    /// use malachite_q::Rational;
146    ///
147    /// assert_eq!(&Rational::ONE_HALF - Rational::ONE_HALF, 0);
148    /// assert_eq!(
149    ///     (&Rational::from_signeds(22, 7) - Rational::from_signeds(99, 100)).to_string(),
150    ///     "1507/700"
151    /// );
152    /// ```
153    fn sub(self, other: Rational) -> Rational {
154        if *self == 0u32 {
155            return -other;
156        } else if other == 0u32 {
157            return self.clone();
158        }
159        let mut gcd = (&self.denominator).gcd(&other.denominator);
160        if gcd == 1u32 {
161            let diff_n =
162                Integer::from_sign_and_abs(self.sign, &self.numerator * &other.denominator)
163                    - Integer::from_sign_and_abs(other.sign, other.numerator * &self.denominator);
164            let diff_d = &self.denominator * other.denominator;
165            Rational {
166                sign: diff_n >= 0,
167                numerator: diff_n.unsigned_abs(),
168                denominator: diff_d,
169            }
170        } else {
171            let reduced_self_d = (&self.denominator).div_exact(&gcd);
172            let diff_n =
173                Integer::from_sign_and_abs(
174                    self.sign,
175                    &self.numerator * (&other.denominator).div_exact(&gcd),
176                ) - Integer::from_sign_and_abs(other.sign, other.numerator * &reduced_self_d);
177            gcd.gcd_assign(diff_n.unsigned_abs_ref());
178            if gcd == 1u32 {
179                Rational {
180                    sign: diff_n >= 0,
181                    numerator: diff_n.unsigned_abs(),
182                    denominator: other.denominator * reduced_self_d,
183                }
184            } else {
185                Rational {
186                    sign: diff_n >= 0,
187                    numerator: diff_n.unsigned_abs().div_exact(&gcd),
188                    denominator: (other.denominator).div_exact(gcd) * reduced_self_d,
189                }
190            }
191        }
192    }
193}
194
195impl Sub<&Rational> for &Rational {
196    type Output = Rational;
197
198    /// Subtracts a [`Rational`] by another [`Rational`], taking both by reference.
199    ///
200    /// $$
201    /// f(x, y) = x - y.
202    /// $$
203    ///
204    /// # Worst-case complexity
205    /// $T(n) = O(n (\log n)^2 \log\log n)$
206    ///
207    /// $M(n) = O(n \log n)$
208    ///
209    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
210    /// other.significant_bits())`.
211    ///
212    /// # Examples
213    /// ```
214    /// use malachite_base::num::basic::traits::OneHalf;
215    /// use malachite_q::Rational;
216    ///
217    /// assert_eq!(&Rational::ONE_HALF - &Rational::ONE_HALF, 0);
218    /// assert_eq!(
219    ///     (&Rational::from_signeds(22, 7) - &Rational::from_signeds(99, 100)).to_string(),
220    ///     "1507/700"
221    /// );
222    /// ```
223    fn sub(self, other: &Rational) -> Rational {
224        if *self == 0u32 {
225            return -other.clone();
226        } else if *other == 0u32 {
227            return self.clone();
228        }
229        let mut gcd = (&self.denominator).gcd(&other.denominator);
230        if gcd == 1u32 {
231            let diff_n =
232                Integer::from_sign_and_abs(self.sign, &self.numerator * &other.denominator)
233                    - Integer::from_sign_and_abs(other.sign, &other.numerator * &self.denominator);
234            let diff_d = &self.denominator * &other.denominator;
235            Rational {
236                sign: diff_n >= 0,
237                numerator: diff_n.unsigned_abs(),
238                denominator: diff_d,
239            }
240        } else {
241            let reduced_self_d = (&self.denominator).div_exact(&gcd);
242            let diff_n =
243                Integer::from_sign_and_abs(
244                    self.sign,
245                    &self.numerator * (&other.denominator).div_exact(&gcd),
246                ) - Integer::from_sign_and_abs(other.sign, &other.numerator * &reduced_self_d);
247            gcd.gcd_assign(diff_n.unsigned_abs_ref());
248            if gcd == 1u32 {
249                Rational {
250                    sign: diff_n >= 0,
251                    numerator: diff_n.unsigned_abs(),
252                    denominator: &other.denominator * reduced_self_d,
253                }
254            } else {
255                Rational {
256                    sign: diff_n >= 0,
257                    numerator: diff_n.unsigned_abs().div_exact(&gcd),
258                    denominator: (&other.denominator).div_exact(gcd) * reduced_self_d,
259                }
260            }
261        }
262    }
263}
264
265impl SubAssign<Self> for Rational {
266    /// Subtracts a [`Rational`] by another [`Rational`] in place, taking the [`Rational`] on the
267    /// right-hand side by value.
268    ///
269    /// $$
270    /// x \gets x - y.
271    /// $$
272    ///
273    /// # Worst-case complexity
274    /// $T(n) = O(n (\log n)^2 \log\log n)$
275    ///
276    /// $M(n) = O(n \log n)$
277    ///
278    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
279    /// other.significant_bits())`.
280    ///
281    /// # Examples
282    /// ```
283    /// use malachite_base::num::basic::traits::OneHalf;
284    /// use malachite_q::Rational;
285    ///
286    /// let mut x = Rational::ONE_HALF;
287    /// x -= Rational::ONE_HALF;
288    /// assert_eq!(x, 0);
289    ///
290    /// let mut x = Rational::from_signeds(22, 7);
291    /// x -= Rational::from_signeds(99, 100);
292    /// assert_eq!(x.to_string(), "1507/700");
293    /// ```
294    fn sub_assign(&mut self, other: Self) {
295        if *self == 0u32 {
296            *self = -other;
297            return;
298        } else if other == 0u32 {
299            return;
300        }
301        let mut gcd = (&self.denominator).gcd(&other.denominator);
302        if gcd == 1u32 {
303            self.numerator *= &other.denominator;
304            let diff_n = Integer::from_sign_and_abs_ref(self.sign, &self.numerator)
305                - Integer::from_sign_and_abs(other.sign, other.numerator * &self.denominator);
306            self.sign = diff_n >= 0;
307            self.numerator = diff_n.unsigned_abs();
308            self.denominator *= other.denominator;
309        } else {
310            self.denominator.div_exact_assign(&gcd);
311            self.numerator *= (&other.denominator).div_exact(&gcd);
312            let diff_n = Integer::from_sign_and_abs_ref(self.sign, &self.numerator)
313                - Integer::from_sign_and_abs(other.sign, other.numerator * &self.denominator);
314            gcd.gcd_assign(diff_n.unsigned_abs_ref());
315            self.sign = diff_n >= 0;
316            if gcd == 1u32 {
317                self.numerator = diff_n.unsigned_abs();
318                self.denominator *= other.denominator;
319            } else {
320                self.numerator = diff_n.unsigned_abs().div_exact(&gcd);
321                self.denominator *= (other.denominator).div_exact(gcd);
322            }
323        }
324    }
325}
326
327impl SubAssign<&Self> for Rational {
328    /// Subtracts a [`Rational`] by another [`Rational`] in place, taking the [`Rational`] on the
329    /// right-hand side by reference.
330    ///
331    /// $$
332    /// x \gets x - y.
333    /// $$
334    ///
335    /// # Worst-case complexity
336    /// $T(n) = O(n (\log n)^2 \log\log n)$
337    ///
338    /// $M(n) = O(n \log n)$
339    ///
340    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
341    /// other.significant_bits())`.
342    ///
343    /// # Examples
344    /// ```
345    /// use malachite_base::num::basic::traits::OneHalf;
346    /// use malachite_q::Rational;
347    ///
348    /// let mut x = Rational::ONE_HALF;
349    /// x -= &Rational::ONE_HALF;
350    /// assert_eq!(x, 0);
351    ///
352    /// let mut x = Rational::from_signeds(22, 7);
353    /// x -= &Rational::from_signeds(99, 100);
354    /// assert_eq!(x.to_string(), "1507/700");
355    /// ```
356    fn sub_assign(&mut self, other: &Self) {
357        if *self == 0u32 {
358            self.clone_from(other);
359            self.neg_assign();
360            return;
361        } else if *other == 0u32 {
362            return;
363        }
364        let mut gcd = (&self.denominator).gcd(&other.denominator);
365        if gcd == 1u32 {
366            self.numerator *= &other.denominator;
367            let diff_n = Integer::from_sign_and_abs_ref(self.sign, &self.numerator)
368                - Integer::from_sign_and_abs(other.sign, &other.numerator * &self.denominator);
369            self.sign = diff_n >= 0;
370            self.numerator = diff_n.unsigned_abs();
371            self.denominator *= &other.denominator;
372        } else {
373            self.denominator.div_exact_assign(&gcd);
374            self.numerator *= (&other.denominator).div_exact(&gcd);
375            let diff_n = Integer::from_sign_and_abs_ref(self.sign, &self.numerator)
376                - Integer::from_sign_and_abs(other.sign, &other.numerator * &self.denominator);
377            gcd.gcd_assign(diff_n.unsigned_abs_ref());
378            self.sign = diff_n >= 0;
379            if gcd == 1u32 {
380                self.numerator = diff_n.unsigned_abs();
381                self.denominator *= &other.denominator;
382            } else {
383                self.numerator = diff_n.unsigned_abs().div_exact(&gcd);
384                self.denominator *= (&other.denominator).div_exact(gcd);
385            }
386        }
387    }
388}