malachite_q/arithmetic/
mul.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5//      Copyright © 1991, 1994-1996, 2000-2002 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::Product;
16use core::ops::{Mul, MulAssign};
17use malachite_base::num::arithmetic::traits::{DivExact, DivExactAssign, Gcd};
18use malachite_base::num::basic::traits::{One, Zero};
19
20impl Mul<Self> for Rational {
21    type Output = Self;
22
23    /// Multiplies two [`Rational`]s, taking both by value.
24    ///
25    /// $$
26    /// f(x, y) = xy.
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, Two};
40    /// use malachite_q::Rational;
41    ///
42    /// assert_eq!(Rational::ONE_HALF * Rational::TWO, 1);
43    /// assert_eq!(
44    ///     (Rational::from_signeds(22, 7) * Rational::from_signeds(99, 100)).to_string(),
45    ///     "1089/350"
46    /// );
47    /// ```
48    fn mul(self, other: Self) -> Self {
49        if self == 0u32 || other == 0u32 {
50            return Self::ZERO;
51        } else if self == 1u32 {
52            return other;
53        } else if other == 1u32 {
54            return self;
55        }
56        let g_1 = (&self.numerator).gcd(&other.denominator);
57        let g_2 = (&other.numerator).gcd(&self.denominator);
58        Self {
59            sign: self.sign == other.sign,
60            numerator: (self.numerator).div_exact(&g_1) * (other.numerator).div_exact(&g_2),
61            denominator: (other.denominator).div_exact(g_1) * (self.denominator).div_exact(g_2),
62        }
63    }
64}
65
66impl Mul<&Self> for Rational {
67    type Output = Self;
68
69    /// Multiplies two [`Rational`]s, taking the first by value and the second by reference.
70    ///
71    /// $$
72    /// f(x, y) = xy.
73    /// $$
74    ///
75    /// # Worst-case complexity
76    /// $T(n) = O(n (\log n)^2 \log\log n)$
77    ///
78    /// $M(n) = O(n \log n)$
79    ///
80    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
81    /// other.significant_bits())`.
82    ///
83    /// # Examples
84    /// ```
85    /// use malachite_base::num::basic::traits::{OneHalf, Two};
86    /// use malachite_q::Rational;
87    ///
88    /// assert_eq!(Rational::ONE_HALF * &Rational::TWO, 1);
89    /// assert_eq!(
90    ///     (Rational::from_signeds(22, 7) * &Rational::from_signeds(99, 100)).to_string(),
91    ///     "1089/350"
92    /// );
93    /// ```
94    #[inline]
95    fn mul(self, other: &Self) -> Self {
96        other * self
97    }
98}
99
100impl Mul<Rational> for &Rational {
101    type Output = Rational;
102
103    /// Multiplies two [`Rational`]s, taking the first by reference and the second by value.
104    ///
105    /// $$
106    /// f(x, y) = xy.
107    /// $$
108    ///
109    /// # Worst-case complexity
110    /// $T(n) = O(n (\log n)^2 \log\log n)$
111    ///
112    /// $M(n) = O(n \log n)$
113    ///
114    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
115    /// other.significant_bits())`.
116    ///
117    /// # Examples
118    /// ```
119    /// use malachite_base::num::basic::traits::{OneHalf, Two};
120    /// use malachite_q::Rational;
121    ///
122    /// assert_eq!(&Rational::ONE_HALF * Rational::TWO, 1);
123    /// assert_eq!(
124    ///     (&Rational::from_signeds(22, 7) * Rational::from_signeds(99, 100)).to_string(),
125    ///     "1089/350"
126    /// );
127    /// ```
128    fn mul(self, other: Rational) -> Rational {
129        if *self == 0u32 || other == 0u32 {
130            return Rational::ZERO;
131        } else if *self == 1u32 {
132            return other;
133        } else if other == 1u32 {
134            return self.clone();
135        }
136        let g_1 = (&self.numerator).gcd(&other.denominator);
137        let g_2 = (&other.numerator).gcd(&self.denominator);
138        Rational {
139            sign: self.sign == other.sign,
140            numerator: (&self.numerator).div_exact(&g_1) * (other.numerator).div_exact(&g_2),
141            denominator: (other.denominator).div_exact(g_1) * (&self.denominator).div_exact(g_2),
142        }
143    }
144}
145
146impl Mul<&Rational> for &Rational {
147    type Output = Rational;
148
149    /// Multiplies two [`Rational`]s, taking both by reference.
150    ///
151    /// $$
152    /// f(x, y) = xy.
153    /// $$
154    ///
155    /// # Worst-case complexity
156    /// $T(n) = O(n (\log n)^2 \log\log n)$
157    ///
158    /// $M(n) = O(n \log n)$
159    ///
160    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
161    /// other.significant_bits())`.
162    ///
163    /// # Examples
164    /// ```
165    /// use malachite_base::num::basic::traits::{OneHalf, Two};
166    /// use malachite_q::Rational;
167    ///
168    /// assert_eq!(&Rational::ONE_HALF * &Rational::TWO, 1);
169    /// assert_eq!(
170    ///     (&Rational::from_signeds(22, 7) * &Rational::from_signeds(99, 100)).to_string(),
171    ///     "1089/350"
172    /// );
173    /// ```
174    fn mul(self, other: &Rational) -> Rational {
175        if *self == 0u32 || *other == 0u32 {
176            return Rational::ZERO;
177        } else if *self == 1u32 {
178            return other.clone();
179        } else if *other == 1u32 {
180            return self.clone();
181        }
182        let g_1 = (&self.numerator).gcd(&other.denominator);
183        let g_2 = (&other.numerator).gcd(&self.denominator);
184        Rational {
185            sign: self.sign == other.sign,
186            numerator: (&self.numerator).div_exact(&g_1) * (&other.numerator).div_exact(&g_2),
187            denominator: (&other.denominator).div_exact(g_1) * (&self.denominator).div_exact(g_2),
188        }
189    }
190}
191
192impl MulAssign<Self> for Rational {
193    /// Multiplies a [`Rational`] by a [`Rational`] in place, taking the [`Rational`] on the
194    /// right-hand side by value.
195    ///
196    /// $$
197    /// x \gets xy.
198    /// $$
199    ///
200    /// # Worst-case complexity
201    /// $T(n) = O(n (\log n)^2 \log\log n)$
202    ///
203    /// $M(n) = O(n \log n)$
204    ///
205    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
206    /// other.significant_bits())`.
207    ///
208    /// # Examples
209    /// ```
210    /// use malachite_base::num::basic::traits::{OneHalf, Two};
211    /// use malachite_q::Rational;
212    ///
213    /// let mut x = Rational::ONE_HALF;
214    /// x *= Rational::TWO;
215    /// assert_eq!(x, 1);
216    ///
217    /// let mut x = Rational::from_signeds(22, 7);
218    /// x *= Rational::from_signeds(99, 100);
219    /// assert_eq!(x.to_string(), "1089/350");
220    /// ```
221    fn mul_assign(&mut self, other: Self) {
222        if *self == 0u32 || other == 1u32 {
223            return;
224        } else if other == 0u32 {
225            *self = Self::ZERO;
226            return;
227        } else if *self == 1u32 {
228            *self = other;
229            return;
230        }
231        self.sign = self.sign == other.sign;
232        let g_1 = (&self.numerator).gcd(&other.denominator);
233        let g_2 = (&other.numerator).gcd(&self.denominator);
234        self.numerator.div_exact_assign(&g_1);
235        self.denominator.div_exact_assign(&g_2);
236        self.numerator *= (other.numerator).div_exact(g_2);
237        self.denominator *= (other.denominator).div_exact(g_1);
238    }
239}
240
241impl MulAssign<&Self> for Rational {
242    /// Multiplies a [`Rational`] by a [`Rational`] in place, taking the [`Rational`] on the
243    /// right-hand side by reference.
244    ///
245    /// $$
246    /// x \gets xy.
247    /// $$
248    ///
249    /// # Worst-case complexity
250    /// $T(n) = O(n (\log n)^3 \log\log n)$
251    ///
252    /// $M(n) = O(n \log n)$
253    ///
254    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
255    /// other.significant_bits())`.
256    ///
257    /// # Examples
258    /// ```
259    /// use malachite_base::num::basic::traits::{OneHalf, Two};
260    /// use malachite_q::Rational;
261    ///
262    /// let mut x = Rational::ONE_HALF;
263    /// x *= &Rational::TWO;
264    /// assert_eq!(x, 1);
265    ///
266    /// let mut x = Rational::from_signeds(22, 7);
267    /// x *= &Rational::from_signeds(99, 100);
268    /// assert_eq!(x.to_string(), "1089/350");
269    /// ```
270    fn mul_assign(&mut self, other: &Self) {
271        if *self == 0u32 || *other == 1u32 {
272            return;
273        } else if *other == 0u32 {
274            *self = Self::ZERO;
275            return;
276        } else if *self == 1u32 {
277            *self = other.clone();
278            return;
279        }
280        self.sign = self.sign == other.sign;
281        let g_1 = (&self.numerator).gcd(&other.denominator);
282        let g_2 = (&other.numerator).gcd(&self.denominator);
283        self.numerator.div_exact_assign(&g_1);
284        self.denominator.div_exact_assign(&g_2);
285        self.numerator *= (&other.numerator).div_exact(g_2);
286        self.denominator *= (&other.denominator).div_exact(g_1);
287    }
288}
289
290impl Product for Rational {
291    /// Multiplies together all the [`Rational`]s in an iterator.
292    ///
293    /// $$
294    /// f((x_i)_ {i=0}^{n-1}) = \prod_ {i=0}^{n-1} x_i.
295    /// $$
296    ///
297    /// # Worst-case complexity
298    /// $T(n) = O(n (\log n)^3 \log\log n)$
299    ///
300    /// $M(n) = O(n \log n)$
301    ///
302    /// where $T$ is time, $M$ is additional memory, and $n$ is
303    /// `Rational::sum(xs.map(Rational::significant_bits))`.
304    ///
305    /// # Examples
306    /// ```
307    /// use malachite_base::vecs::vec_from_str;
308    /// use malachite_q::Rational;
309    /// use std::iter::Product;
310    ///
311    /// assert_eq!(
312    ///     Rational::product(
313    ///         vec_from_str::<Rational>("[1, 2/3, 3/4, 4/5, 5/6, 6/7, 7/8, 8/9, 9/10]")
314    ///             .unwrap()
315    ///             .into_iter()
316    ///     )
317    ///     .to_string(),
318    ///     "1/5"
319    /// );
320    /// ```
321    fn product<I>(xs: I) -> Self
322    where
323        I: Iterator<Item = Self>,
324    {
325        let mut stack = Vec::new();
326        for (i, x) in xs.enumerate() {
327            if x == 0 {
328                return Self::ZERO;
329            }
330            let mut p = x;
331            for _ in 0..(i + 1).trailing_zeros() {
332                p *= stack.pop().unwrap();
333            }
334            stack.push(p);
335        }
336        let mut p = Self::ONE;
337        for x in stack.into_iter().rev() {
338            p *= x;
339        }
340        p
341    }
342}
343
344impl<'a> Product<&'a Self> for Rational {
345    /// Multiplies together all the [`Rational`]s in an iterator of [`Rational`] references.
346    ///
347    /// $$
348    /// f((x_i)_ {i=0}^{n-1}) = \prod_ {i=0}^{n-1} x_i.
349    /// $$
350    ///
351    /// # Worst-case complexity
352    /// $T(n) = O(n (\log n)^2 \log\log n)$
353    ///
354    /// $M(n) = O(n \log n)$
355    ///
356    /// where $T$ is time, $M$ is additional memory, and $n$ is
357    /// `Rational::sum(xs.map(Rational::significant_bits))`.
358    ///
359    /// # Examples
360    /// ```
361    /// use malachite_base::vecs::vec_from_str;
362    /// use malachite_q::Rational;
363    /// use std::iter::Product;
364    ///
365    /// assert_eq!(
366    ///     Rational::product(
367    ///         vec_from_str::<Rational>("[1, 2/3, 3/4, 4/5, 5/6, 6/7, 7/8, 8/9, 9/10]")
368    ///             .unwrap()
369    ///             .iter()
370    ///     )
371    ///     .to_string(),
372    ///     "1/5"
373    /// );
374    /// ```
375    fn product<I>(xs: I) -> Self
376    where
377        I: Iterator<Item = &'a Self>,
378    {
379        let mut stack = Vec::new();
380        for (i, x) in xs.enumerate() {
381            if *x == 0 {
382                return Self::ZERO;
383            }
384            let mut p = x.clone();
385            for _ in 0..(i + 1).trailing_zeros() {
386                p *= stack.pop().unwrap();
387            }
388            stack.push(p);
389        }
390        let mut p = Self::ONE;
391        for x in stack.into_iter().rev() {
392            p *= x;
393        }
394        p
395    }
396}