malachite_q/arithmetic/
add.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 alloc::vec::Vec;
15use core::iter::Sum;
16use core::ops::{Add, AddAssign};
17use malachite_base::num::arithmetic::traits::{
18    DivExact, DivExactAssign, Gcd, GcdAssign, UnsignedAbs,
19};
20use malachite_base::num::basic::traits::Zero;
21use malachite_nz::integer::Integer;
22
23impl Add<Self> for Rational {
24    type Output = Self;
25
26    /// Adds two [`Rational`]s, taking both by value.
27    ///
28    /// $$
29    /// f(x, y) = x + y.
30    /// $$
31    ///
32    /// # Worst-case complexity
33    /// $T(n) = O(n (\log n)^2 \log\log n)$
34    ///
35    /// $M(n) = O(n \log n)$
36    ///
37    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
38    /// other.significant_bits())`.
39    ///
40    /// # Examples
41    /// ```
42    /// use malachite_base::num::basic::traits::OneHalf;
43    /// use malachite_q::Rational;
44    ///
45    /// assert_eq!(Rational::ONE_HALF + Rational::ONE_HALF, 1);
46    /// assert_eq!(
47    ///     (Rational::from_signeds(22, 7) + Rational::from_signeds(99, 100)).to_string(),
48    ///     "2893/700"
49    /// );
50    /// ```
51    fn add(self, other: Self) -> Self {
52        if self == 0u32 {
53            return other;
54        } else if other == 0u32 {
55            return self;
56        }
57        let mut gcd = (&self.denominator).gcd(&other.denominator);
58        if gcd == 1u32 {
59            let sum_n = Integer::from_sign_and_abs(self.sign, self.numerator * &other.denominator)
60                + Integer::from_sign_and_abs(other.sign, other.numerator * &self.denominator);
61            let sum_d = self.denominator * other.denominator;
62            Self {
63                sign: sum_n >= 0,
64                numerator: sum_n.unsigned_abs(),
65                denominator: sum_d,
66            }
67        } else {
68            let reduced_self_d = (self.denominator).div_exact(&gcd);
69            let sum_n =
70                Integer::from_sign_and_abs(
71                    self.sign,
72                    self.numerator * (&other.denominator).div_exact(&gcd),
73                ) + Integer::from_sign_and_abs(other.sign, other.numerator * &reduced_self_d);
74            gcd.gcd_assign(sum_n.unsigned_abs_ref());
75            if gcd == 1u32 {
76                Self {
77                    sign: sum_n >= 0,
78                    numerator: sum_n.unsigned_abs(),
79                    denominator: other.denominator * reduced_self_d,
80                }
81            } else {
82                Self {
83                    sign: sum_n >= 0,
84                    numerator: sum_n.unsigned_abs().div_exact(&gcd),
85                    denominator: (other.denominator).div_exact(gcd) * reduced_self_d,
86                }
87            }
88        }
89    }
90}
91
92impl Add<&Self> for Rational {
93    type Output = Self;
94
95    /// Adds two [`Rational`]s, taking both by the first by value and the second by reference.
96    ///
97    /// $$
98    /// f(x, y) = x + y.
99    /// $$
100    ///
101    /// # Worst-case complexity
102    /// $T(n) = O(n (\log n)^2 \log\log n)$
103    ///
104    /// $M(n) = O(n \log n)$
105    ///
106    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
107    /// other.significant_bits())`.
108    ///
109    /// # Examples
110    /// ```
111    /// use malachite_base::num::basic::traits::OneHalf;
112    /// use malachite_q::Rational;
113    ///
114    /// assert_eq!(Rational::ONE_HALF + &Rational::ONE_HALF, 1);
115    /// assert_eq!(
116    ///     (Rational::from_signeds(22, 7) + &Rational::from_signeds(99, 100)).to_string(),
117    ///     "2893/700"
118    /// );
119    /// ```
120    #[inline]
121    fn add(self, other: &Self) -> Self {
122        other + self
123    }
124}
125
126impl Add<Rational> for &Rational {
127    type Output = Rational;
128
129    /// Adds two [`Rational`]s, taking the first by reference and the second by value
130    ///
131    /// $$
132    /// f(x, y) = x + y.
133    /// $$
134    ///
135    /// # Worst-case complexity
136    /// $T(n) = O(n (\log n)^2 \log\log n)$
137    ///
138    /// $M(n) = O(n \log n)$
139    ///
140    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
141    /// other.significant_bits())`.
142    ///
143    /// # Examples
144    /// ```
145    /// use malachite_base::num::basic::traits::OneHalf;
146    /// use malachite_q::Rational;
147    ///
148    /// assert_eq!(&Rational::ONE_HALF + Rational::ONE_HALF, 1);
149    /// assert_eq!(
150    ///     (&Rational::from_signeds(22, 7) + Rational::from_signeds(99, 100)).to_string(),
151    ///     "2893/700"
152    /// );
153    /// ```
154    fn add(self, other: Rational) -> Rational {
155        if *self == 0u32 {
156            return other;
157        } else if other == 0u32 {
158            return self.clone();
159        }
160        let mut gcd = (&self.denominator).gcd(&other.denominator);
161        if gcd == 1u32 {
162            let sum_n = 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 sum_d = &self.denominator * other.denominator;
165            Rational {
166                sign: sum_n >= 0,
167                numerator: sum_n.unsigned_abs(),
168                denominator: sum_d,
169            }
170        } else {
171            let reduced_self_d = (&self.denominator).div_exact(&gcd);
172            let sum_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(sum_n.unsigned_abs_ref());
178            if gcd == 1u32 {
179                Rational {
180                    sign: sum_n >= 0,
181                    numerator: sum_n.unsigned_abs(),
182                    denominator: other.denominator * reduced_self_d,
183                }
184            } else {
185                Rational {
186                    sign: sum_n >= 0,
187                    numerator: sum_n.unsigned_abs().div_exact(&gcd),
188                    denominator: (other.denominator).div_exact(gcd) * reduced_self_d,
189                }
190            }
191        }
192    }
193}
194
195impl Add<&Rational> for &Rational {
196    type Output = Rational;
197
198    /// Adds two [`Rational`]s, 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, 1);
218    /// assert_eq!(
219    ///     (&Rational::from_signeds(22, 7) + &Rational::from_signeds(99, 100)).to_string(),
220    ///     "2893/700"
221    /// );
222    /// ```
223    fn add(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 sum_n = Integer::from_sign_and_abs(self.sign, &self.numerator * &other.denominator)
232                + Integer::from_sign_and_abs(other.sign, &other.numerator * &self.denominator);
233            let sum_d = &self.denominator * &other.denominator;
234            Rational {
235                sign: sum_n >= 0,
236                numerator: sum_n.unsigned_abs(),
237                denominator: sum_d,
238            }
239        } else {
240            let reduced_self_d = (&self.denominator).div_exact(&gcd);
241            let sum_n =
242                Integer::from_sign_and_abs(
243                    self.sign,
244                    &self.numerator * (&other.denominator).div_exact(&gcd),
245                ) + Integer::from_sign_and_abs(other.sign, &other.numerator * &reduced_self_d);
246            gcd.gcd_assign(sum_n.unsigned_abs_ref());
247            if gcd == 1u32 {
248                Rational {
249                    sign: sum_n >= 0,
250                    numerator: sum_n.unsigned_abs(),
251                    denominator: &other.denominator * reduced_self_d,
252                }
253            } else {
254                Rational {
255                    sign: sum_n >= 0,
256                    numerator: sum_n.unsigned_abs().div_exact(&gcd),
257                    denominator: (&other.denominator).div_exact(gcd) * reduced_self_d,
258                }
259            }
260        }
261    }
262}
263
264impl AddAssign<Self> for Rational {
265    /// Adds a [`Rational`] to a [`Rational`] in place, taking the [`Rational`] on the right-hand
266    /// side by value.
267    ///
268    /// $$
269    /// x \gets x + y.
270    /// $$
271    ///
272    /// # Worst-case complexity
273    /// $T(n) = O(n (\log n)^2 \log\log n)$
274    ///
275    /// $M(n) = O(n \log n)$
276    ///
277    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
278    /// other.significant_bits())`.
279    ///
280    /// # Examples
281    /// ```
282    /// use malachite_base::num::basic::traits::OneHalf;
283    /// use malachite_q::Rational;
284    ///
285    /// let mut x = Rational::ONE_HALF;
286    /// x += Rational::ONE_HALF;
287    /// assert_eq!(x, 1);
288    ///
289    /// let mut x = Rational::from_signeds(22, 7);
290    /// x += Rational::from_signeds(99, 100);
291    /// assert_eq!(x.to_string(), "2893/700");
292    /// ```
293    fn add_assign(&mut self, other: Self) {
294        if *self == 0u32 {
295            *self = other;
296            return;
297        } else if other == 0u32 {
298            return;
299        }
300        let mut gcd = (&self.denominator).gcd(&other.denominator);
301        if gcd == 1u32 {
302            self.numerator *= &other.denominator;
303            let sum_n = Integer::from_sign_and_abs_ref(self.sign, &self.numerator)
304                + Integer::from_sign_and_abs(other.sign, other.numerator * &self.denominator);
305            self.sign = sum_n >= 0;
306            self.numerator = sum_n.unsigned_abs();
307            self.denominator *= other.denominator;
308        } else {
309            self.denominator.div_exact_assign(&gcd);
310            self.numerator *= (&other.denominator).div_exact(&gcd);
311            let sum_n = Integer::from_sign_and_abs_ref(self.sign, &self.numerator)
312                + Integer::from_sign_and_abs(other.sign, other.numerator * &self.denominator);
313            gcd.gcd_assign(sum_n.unsigned_abs_ref());
314            self.sign = sum_n >= 0;
315            if gcd == 1u32 {
316                self.numerator = sum_n.unsigned_abs();
317                self.denominator *= other.denominator;
318            } else {
319                self.numerator = sum_n.unsigned_abs().div_exact(&gcd);
320                self.denominator *= (other.denominator).div_exact(gcd);
321            }
322        }
323    }
324}
325
326impl AddAssign<&Self> for Rational {
327    /// Adds a [`Rational`] to a [`Rational`] in place, taking the [`Rational`] on the right-hand
328    /// side by reference.
329    ///
330    /// $$
331    /// x \gets x + y.
332    /// $$
333    ///
334    /// # Worst-case complexity
335    /// $T(n) = O(n (\log n)^2 \log\log n)$
336    ///
337    /// $M(n) = O(n \log n)$
338    ///
339    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
340    /// other.significant_bits())`.
341    ///
342    /// # Examples
343    /// ```
344    /// use malachite_base::num::basic::traits::OneHalf;
345    /// use malachite_q::Rational;
346    ///
347    /// let mut x = Rational::ONE_HALF;
348    /// x += &Rational::ONE_HALF;
349    /// assert_eq!(x, 1);
350    ///
351    /// let mut x = Rational::from_signeds(22, 7);
352    /// x += &Rational::from_signeds(99, 100);
353    /// assert_eq!(x.to_string(), "2893/700");
354    /// ```
355    fn add_assign(&mut self, other: &Self) {
356        if *self == 0u32 {
357            self.clone_from(other);
358            return;
359        } else if *other == 0u32 {
360            return;
361        }
362        let mut gcd = (&self.denominator).gcd(&other.denominator);
363        if gcd == 1u32 {
364            self.numerator *= &other.denominator;
365            let sum_n = Integer::from_sign_and_abs_ref(self.sign, &self.numerator)
366                + Integer::from_sign_and_abs(other.sign, &other.numerator * &self.denominator);
367            self.sign = sum_n >= 0;
368            self.numerator = sum_n.unsigned_abs();
369            self.denominator *= &other.denominator;
370        } else {
371            self.denominator.div_exact_assign(&gcd);
372            self.numerator *= (&other.denominator).div_exact(&gcd);
373            let sum_n = Integer::from_sign_and_abs_ref(self.sign, &self.numerator)
374                + Integer::from_sign_and_abs(other.sign, &other.numerator * &self.denominator);
375            gcd.gcd_assign(sum_n.unsigned_abs_ref());
376            self.sign = sum_n >= 0;
377            if gcd == 1u32 {
378                self.numerator = sum_n.unsigned_abs();
379                self.denominator *= &other.denominator;
380            } else {
381                self.numerator = sum_n.unsigned_abs().div_exact(&gcd);
382                self.denominator *= (&other.denominator).div_exact(gcd);
383            }
384        }
385    }
386}
387
388impl Sum for Rational {
389    /// Adds up all the [`Rational`]s in an iterator.
390    ///
391    /// $$
392    /// f((x_i)_ {i=0}^{n-1}) = \sum_ {i=0}^{n-1} x_i.
393    /// $$
394    ///
395    /// # Worst-case complexity
396    /// $T(n) = O(n (\log n)^3 \log\log n)$
397    ///
398    /// $M(n) = O(n \log n)$
399    ///
400    /// where $T$ is time, $M$ is additional memory, and $n$ is
401    /// `Rational::sum(xs.map(Rational::significant_bits))`.
402    ///
403    /// # Examples
404    /// ```
405    /// use malachite_base::vecs::vec_from_str;
406    /// use malachite_q::Rational;
407    /// use std::iter::Sum;
408    ///
409    /// assert_eq!(
410    ///     Rational::sum(
411    ///         vec_from_str::<Rational>("[0, 1, 2/3, 3/4, 4/5, 5/6, 6/7, 7/8, 8/9, 9/10]")
412    ///             .unwrap()
413    ///             .into_iter()
414    ///     )
415    ///     .to_string(),
416    ///     "19079/2520"
417    /// );
418    /// ```
419    fn sum<I>(xs: I) -> Self
420    where
421        I: Iterator<Item = Self>,
422    {
423        let mut stack = Vec::new();
424        for (i, x) in xs.enumerate() {
425            let mut s = x;
426            for _ in 0..(i + 1).trailing_zeros() {
427                s += stack.pop().unwrap();
428            }
429            stack.push(s);
430        }
431        let mut s = Self::ZERO;
432        for x in stack.into_iter().rev() {
433            s += x;
434        }
435        s
436    }
437}
438
439impl<'a> Sum<&'a Self> for Rational {
440    /// Adds up all the [`Rational`]s in an iterator of [`Rational`] references.
441    ///
442    /// $$
443    /// f((x_i)_ {i=0}^{n-1}) = \sum_ {i=0}^{n-1} x_i.
444    /// $$
445    ///
446    /// # Worst-case complexity
447    /// $T(n) = O(n (\log n)^3 \log\log n)$
448    ///
449    /// $M(n) = O(n \log n)$
450    ///
451    /// where $T$ is time, $M$ is additional memory, and $n$ is
452    /// `Rational::sum(xs.map(Rational::significant_bits))`.
453    ///
454    /// # Examples
455    /// ```
456    /// use malachite_base::vecs::vec_from_str;
457    /// use malachite_q::Rational;
458    /// use std::iter::Sum;
459    ///
460    /// assert_eq!(
461    ///     Rational::sum(
462    ///         vec_from_str::<Rational>("[0, 1, 2/3, 3/4, 4/5, 5/6, 6/7, 7/8, 8/9, 9/10]")
463    ///             .unwrap()
464    ///             .iter()
465    ///     )
466    ///     .to_string(),
467    ///     "19079/2520"
468    /// );
469    /// ```
470    fn sum<I>(xs: I) -> Self
471    where
472        I: Iterator<Item = &'a Self>,
473    {
474        let mut stack = Vec::new();
475        for (i, x) in xs.enumerate() {
476            let mut s = x.clone();
477            for _ in 0..(i + 1).trailing_zeros() {
478                s += stack.pop().unwrap();
479            }
480            stack.push(s);
481        }
482        let mut s = Self::ZERO;
483        for x in stack.into_iter().rev() {
484            s += x;
485        }
486        s
487    }
488}