qfall_math/rational/q/arithmetic/
mul.rs

1// Copyright © 2023 Phil Milewski
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! Implementation of the [`Mul`] trait for [`Q`] values.
10
11use super::super::Q;
12use crate::{
13    integer::Z,
14    macros::arithmetics::{
15        arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
16        arithmetic_between_types, arithmetic_trait_borrowed_to_owned,
17        arithmetic_trait_mixed_borrowed_owned,
18    },
19};
20use flint_sys::fmpq::{fmpq_mul, fmpq_mul_fmpz, fmpq_mul_si, fmpq_mul_ui};
21use std::ops::{Mul, MulAssign};
22
23impl MulAssign<&Q> for Q {
24    /// Computes the multiplication of `self` and `other` reusing
25    /// the memory of `self`.
26    /// [`MulAssign`] can be used on [`Q`] in combination with
27    /// [`Q`], [`Z`], [`f64`], [`f32`], [`i64`], [`i32`], [`i16`], [`i8`], [`u64`], [`u32`], [`u16`] and [`u8`].
28    ///
29    /// Parameters:
30    ///  - `other`: specifies the value to multiply to `self`
31    ///
32    /// Returns the product of both rationals as a [`Q`].
33    ///
34    /// # Examples
35    /// ```
36    /// use qfall_math::{rational::Q, integer::Z};
37    ///
38    /// let mut a: Q = Q::from(42);
39    /// let b: Q = Q::from((-42, 2));
40    /// let c: Z = Z::from(5);
41    ///
42    /// a *= &b;
43    /// a *= b;
44    /// a *= 5;
45    /// a *= c;
46    /// a *= 5.0;
47    /// ```
48    fn mul_assign(&mut self, other: &Self) {
49        unsafe { fmpq_mul(&mut self.value, &self.value, &other.value) };
50    }
51}
52impl MulAssign<&Z> for Q {
53    /// Documentation at [`Q::mul_assign`].
54    fn mul_assign(&mut self, other: &Z) {
55        unsafe { fmpq_mul_fmpz(&mut self.value, &self.value, &other.value) };
56    }
57}
58impl MulAssign<i64> for Q {
59    /// Documentation at [`Q::mul_assign`].
60    fn mul_assign(&mut self, other: i64) {
61        unsafe { fmpq_mul_si(&mut self.value, &self.value, other) };
62    }
63}
64impl MulAssign<u64> for Q {
65    /// Documentation at [`Q::mul_assign`].
66    fn mul_assign(&mut self, other: u64) {
67        unsafe { fmpq_mul_ui(&mut self.value, &self.value, other) };
68    }
69}
70impl MulAssign<f64> for Q {
71    /// Documentation at [`Q::mul_assign`].
72    fn mul_assign(&mut self, other: f64) {
73        let other = Q::from(other);
74
75        unsafe { fmpq_mul(&mut self.value, &self.value, &other.value) };
76    }
77}
78
79arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, Q, Q);
80arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, Q, Z);
81arithmetic_assign_between_types!(MulAssign, mul_assign, Q, i64, i32 i16 i8);
82arithmetic_assign_between_types!(MulAssign, mul_assign, Q, u64, u32 u16 u8);
83arithmetic_assign_between_types!(MulAssign, mul_assign, Q, f64, f32);
84
85impl Mul for &Q {
86    type Output = Q;
87    /// Implements the [`Mul`] trait for two [`Q`] values.
88    /// [`Mul`] is implemented for any combination of [`Q`] and borrowed [`Q`].
89    ///
90    /// Parameters:
91    /// - `other`: specifies the value to multiply with `self`
92    ///
93    /// Returns the product of both numbers as a [`Q`].
94    ///
95    /// # Examples
96    /// ```
97    /// use qfall_math::rational::Q;
98    /// use std::str::FromStr;
99    ///
100    /// let a: Q = Q::from(42);
101    /// let b: Q = Q::from(24);
102    ///
103    /// let c: Q = &a * &b;
104    /// let d: Q = a * b;
105    /// let e: Q = &c * d;
106    /// let f: Q = c * &e;
107    /// ```
108    fn mul(self, other: Self) -> Self::Output {
109        let mut out = Q::default();
110        unsafe {
111            fmpq_mul(&mut out.value, &self.value, &other.value);
112        }
113        out
114    }
115}
116
117arithmetic_trait_borrowed_to_owned!(Mul, mul, Q, Q, Q);
118arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Q, Q, Q);
119arithmetic_between_types!(Mul, mul, Q, Q, i64 i32 i16 i8 u64 u32 u16 u8 f32 f64);
120
121impl Mul<&Z> for &Q {
122    type Output = Q;
123
124    /// Implements the [`Mul`] trait for [`Q`] and [`Z`] values.
125    /// [`Mul`] is implemented for any combination of owned and borrowed values.
126    ///
127    /// Parameters:
128    ///  - `other`: specifies the value to multiply with `self`
129    ///
130    /// Returns the product of both numbers as a [`Q`].
131    ///
132    /// # Examples
133    /// ```
134    /// use qfall_math::rational::Q;
135    /// use qfall_math::integer::Z;
136    /// use std::str::FromStr;
137    ///
138    /// let a: Q = Q::from((42, 19));
139    /// let b: Z = Z::from(-42);
140    ///
141    /// let c: Q = &a * &b;
142    /// let d: Q = a * b;
143    /// let e: Q = &c * Z::from(42);
144    /// let f: Q = c * &Z::from(42);
145    /// ```
146    fn mul(self, other: &Z) -> Self::Output {
147        let mut out = Q::default();
148        unsafe {
149            fmpq_mul_fmpz(&mut out.value, &self.value, &other.value);
150        }
151        out
152    }
153}
154
155arithmetic_trait_borrowed_to_owned!(Mul, mul, Q, Z, Q);
156arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Q, Z, Q);
157
158#[cfg(test)]
159mod test_mul_assign {
160    use crate::{integer::Z, rational::Q};
161
162    /// Ensure that `mul_assign` works for small numbers.
163    #[test]
164    fn correct_small() {
165        let mut a = Q::MINUS_ONE;
166        let b = Q::MINUS_ONE;
167        let c = Q::ZERO;
168        let d = Q::from((-1, 2));
169
170        a *= &b;
171        assert_eq!(1, a);
172        a *= &b;
173        assert_eq!(-1, a);
174        a *= &d;
175        assert_eq!(Q::from((1, 2)), a);
176        a *= &c;
177        assert_eq!(0, a);
178    }
179
180    /// Ensure that `mul_assign` works for large numbers.
181    #[test]
182    fn correct_large() {
183        let mut a: Q = Q::from((2, u64::MAX));
184        let b = Q::from(u64::MAX);
185
186        a *= b;
187
188        assert_eq!(a, Q::from(2));
189    }
190
191    /// Ensure that `mul_assign` is available for all types.
192    #[test]
193    fn availability() {
194        let mut a = Q::from((1, 2));
195        let b = Q::from((4, 5));
196        let c = Z::ONE;
197
198        a *= &b;
199        a *= b;
200        a *= &c;
201        a *= c;
202        a *= 0.5_f64;
203        a *= 0.5_f32;
204        a *= 1_u8;
205        a *= 1_u16;
206        a *= 1_u32;
207        a *= 1_u64;
208        a *= 1_i8;
209        a *= 1_i16;
210        a *= 1_i32;
211        a *= 1_i64;
212    }
213}
214
215#[cfg(test)]
216mod test_mul {
217    use super::Q;
218    use std::str::FromStr;
219
220    /// Testing multiplication for two [`Q`]
221    #[test]
222    fn mul() {
223        let a: Q = Q::from(2);
224        let b: Q = Q::from((42, 2));
225        let c: Q = a * b;
226        assert_eq!(c, Q::from(42));
227    }
228
229    /// Testing multiplication for two borrowed [`Q`]
230    #[test]
231    fn mul_borrow() {
232        let a: Q = Q::from(2);
233        let b: Q = Q::from((42, 2));
234        let c: Q = &a * &b;
235        assert_eq!(c, Q::from(42));
236    }
237
238    /// Testing multiplication for borrowed [`Q`] and [`Q`]
239    #[test]
240    fn mul_first_borrowed() {
241        let a: Q = Q::from(4);
242        let b: Q = Q::from((42, 10));
243        let c: Q = &a * b;
244        assert_eq!(c, Q::from((168, 10)));
245    }
246
247    /// Testing multiplication for [`Q`] and borrowed [`Q`]
248    #[test]
249    fn mul_second_borrowed() {
250        let a: Q = Q::from(2);
251        let b: Q = Q::from((42, 2));
252        let c: Q = a * &b;
253        assert_eq!(c, Q::from(42));
254    }
255
256    /// Testing multiplication for large numerators and divisors
257    #[test]
258    fn mul_large() {
259        let a: Q = Q::from(i64::MAX);
260        let b: Q = Q::from(2);
261        let c: Q = Q::from((1, i32::MAX));
262        let d: Q = Q::from((1, u32::MAX));
263
264        let e: Q = &a * &b;
265        let f: Q = c * d;
266
267        assert_eq!(e, Q::from(u64::MAX - 1));
268        assert_eq!(
269            f,
270            Q::from_str(&format!(
271                "1/{}",
272                u64::from(u32::MAX) * u64::from((u32::MAX - 1) / 2)
273            ))
274            .unwrap()
275        );
276    }
277}
278
279#[cfg(test)]
280mod test_mul_between_q_and_z {
281    use crate::integer::Z;
282    use crate::rational::Q;
283
284    /// Testing multiplication for [`Q`] and [`Z`]
285    #[test]
286    fn mul() {
287        let a: Q = Q::from((5, 7));
288        let b: Z = Z::from(4);
289        let c: Q = a * b;
290        assert_eq!(c, Q::from((20, 7)));
291    }
292
293    /// Testing multiplication for both borrowed [`Q`] and [`Z`]
294    #[test]
295    fn mul_borrow() {
296        let a: Q = Q::from((5, 7));
297        let b: Z = Z::from(4);
298        let c: Q = &a * &b;
299        assert_eq!(c, Q::from((20, 7)));
300    }
301
302    /// Testing multiplication for borrowed [`Q`] and [`Z`]
303    #[test]
304    fn mul_first_borrowed() {
305        let a: Q = Q::from((5, 7));
306        let b: Z = Z::from(4);
307        let c: Q = &a * b;
308        assert_eq!(c, Q::from((20, 7)));
309    }
310
311    /// Testing multiplication for [`Q`] and borrowed [`Z`]
312    #[test]
313    fn mul_second_borrowed() {
314        let a: Q = Q::from((5, 7));
315        let b: Z = Z::from(4);
316        let c: Q = a * &b;
317        assert_eq!(c, Q::from((20, 7)));
318    }
319
320    /// Testing multiplication for large numbers
321    #[test]
322    fn mul_large_numbers() {
323        let a: Q = Q::from((u64::MAX, 2));
324        let b: Q = Q::from((1, u64::MAX));
325        let c: Z = Z::from(u64::MAX);
326
327        let d: Q = a * &c;
328        let e: Q = b * c;
329
330        assert_eq!(d, Q::from(u64::MAX) * Q::from((u64::MAX, 2)));
331        assert_eq!(e, Q::from((1, u64::MAX)) * Q::from(u64::MAX));
332    }
333}
334
335#[cfg(test)]
336mod test_mul_between_types {
337    use crate::rational::Q;
338
339    /// Testing multiplication between different types
340    #[test]
341    #[allow(clippy::op_ref)]
342    fn mul() {
343        let a: Q = Q::from(42);
344        let b: u64 = 1;
345        let c: u32 = 1;
346        let d: u16 = 1;
347        let e: u8 = 1;
348        let f: i64 = 1;
349        let g: i32 = 1;
350        let h: i16 = 1;
351        let i: i8 = 1;
352        let j: f32 = 0.3;
353        let k: f64 = 0.3;
354
355        let _: Q = &a * &b;
356        let _: Q = &a * &c;
357        let _: Q = &a * &d;
358        let _: Q = &a * &e;
359        let _: Q = &a * &f;
360        let _: Q = &a * &g;
361        let _: Q = &a * &h;
362        let _: Q = &a * &i;
363        let _: Q = &a * &j;
364        let _: Q = &a * &k;
365
366        let _: Q = &b * &a;
367        let _: Q = &c * &a;
368        let _: Q = &d * &a;
369        let _: Q = &e * &a;
370        let _: Q = &f * &a;
371        let _: Q = &g * &a;
372        let _: Q = &h * &a;
373        let _: Q = &i * &a;
374        let _: Q = &j * &a;
375        let _: Q = &k * &a;
376
377        let _: Q = &a * b;
378        let _: Q = &a * c;
379        let _: Q = &a * d;
380        let _: Q = &a * e;
381        let _: Q = &a * f;
382        let _: Q = &a * g;
383        let _: Q = &a * h;
384        let _: Q = &a * i;
385        let _: Q = &a * j;
386        let _: Q = &a * k;
387
388        let _: Q = &b * Q::from(42);
389        let _: Q = &c * Q::from(42);
390        let _: Q = &d * Q::from(42);
391        let _: Q = &e * Q::from(42);
392        let _: Q = &f * Q::from(42);
393        let _: Q = &g * Q::from(42);
394        let _: Q = &h * Q::from(42);
395        let _: Q = &i * Q::from(42);
396        let _: Q = &j * Q::from(42);
397        let _: Q = &k * Q::from(42);
398
399        let _: Q = Q::from(42) * &b;
400        let _: Q = Q::from(42) * &c;
401        let _: Q = Q::from(42) * &d;
402        let _: Q = Q::from(42) * &e;
403        let _: Q = Q::from(42) * &f;
404        let _: Q = Q::from(42) * &g;
405        let _: Q = Q::from(42) * &h;
406        let _: Q = Q::from(42) * &i;
407        let _: Q = Q::from(42) * &j;
408        let _: Q = Q::from(42) * &k;
409
410        let _: Q = b * &a;
411        let _: Q = c * &a;
412        let _: Q = d * &a;
413        let _: Q = e * &a;
414        let _: Q = f * &a;
415        let _: Q = g * &a;
416        let _: Q = h * &a;
417        let _: Q = i * &a;
418        let _: Q = j * &a;
419        let _: Q = k * &a;
420
421        let _: Q = Q::from(42) * b;
422        let _: Q = Q::from(42) * c;
423        let _: Q = Q::from(42) * d;
424        let _: Q = Q::from(42) * e;
425        let _: Q = Q::from(42) * f;
426        let _: Q = Q::from(42) * g;
427        let _: Q = Q::from(42) * h;
428        let _: Q = Q::from(42) * i;
429        let _: Q = Q::from(42) * j;
430        let _: Q = Q::from(42) * k;
431
432        let _: Q = b * Q::from(42);
433        let _: Q = c * Q::from(42);
434        let _: Q = d * Q::from(42);
435        let _: Q = e * Q::from(42);
436        let _: Q = f * Q::from(42);
437        let _: Q = g * Q::from(42);
438        let _: Q = h * Q::from(42);
439        let _: Q = i * Q::from(42);
440        let _: Q = j * Q::from(42);
441        let _: Q = k * Q::from(42);
442    }
443}