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}