qfall_math/rational/q/arithmetic/
div.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 [`Div`] trait for [`Q`] values.
10
11use super::super::Q;
12use crate::{
13    error::MathError,
14    integer::Z,
15    macros::arithmetics::{
16        arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
17        arithmetic_between_types, arithmetic_trait_borrowed_to_owned,
18        arithmetic_trait_mixed_borrowed_owned,
19    },
20};
21use flint_sys::fmpq::{fmpq_div, fmpq_div_fmpz, fmpq_is_zero};
22use std::ops::{Div, DivAssign};
23
24impl DivAssign<&Q> for Q {
25    /// Computes the division of `self` and `other` reusing
26    /// the memory of `self`.
27    /// [`DivAssign`] can be used on [`Q`] in combination with
28    /// [`Q`], [`Z`], [`f64`], [`f32`], [`i64`], [`i32`], [`i16`], [`i8`], [`u64`], [`u32`], [`u16`] and [`u8`].
29    ///
30    /// Parameters:
31    ///  - `other`: specifies the value to divide `self` by
32    ///
33    /// Returns the division of both rationals as a [`Q`].
34    ///
35    /// # Examples
36    /// ```
37    /// use qfall_math::{rational::Q, integer::Z};
38    ///
39    /// let mut a: Q = Q::from(42);
40    /// let b: Q = Q::from((-42, 2));
41    /// let c: Z = Z::from(5);
42    ///
43    /// a /= &b;
44    /// a /= b;
45    /// a /= 5;
46    /// a /= c;
47    /// a /= 5.0;
48    /// ```
49    fn div_assign(&mut self, other: &Self) {
50        assert!(!other.is_zero(), "Tried to divide {self} by zero.");
51
52        unsafe { fmpq_div(&mut self.value, &self.value, &other.value) };
53    }
54}
55impl DivAssign<&Z> for Q {
56    /// Documentation at [`Q::div_assign`].
57    fn div_assign(&mut self, other: &Z) {
58        assert!(!other.is_zero(), "Tried to divide {self} by zero.");
59
60        unsafe { fmpq_div_fmpz(&mut self.value, &self.value, &other.value) };
61    }
62}
63impl DivAssign<i64> for Q {
64    /// Documentation at [`Q::div_assign`].
65    fn div_assign(&mut self, other: i64) {
66        assert!(other != 0, "Tried to divide {self} by zero.");
67
68        let other = Z::from(other);
69        unsafe { fmpq_div_fmpz(&mut self.value, &self.value, &other.value) };
70    }
71}
72impl DivAssign<u64> for Q {
73    /// Documentation at [`Q::div_assign`].
74    fn div_assign(&mut self, other: u64) {
75        assert!(other != 0, "Tried to divide {self} by zero.");
76
77        let other = Z::from(other);
78        unsafe { fmpq_div_fmpz(&mut self.value, &self.value, &other.value) };
79    }
80}
81impl DivAssign<f64> for Q {
82    /// Documentation at [`Q::div_assign`].
83    fn div_assign(&mut self, other: f64) {
84        assert!(other != 0.0, "Tried to divide {self} by zero.");
85        let other = Q::from(other);
86
87        unsafe { fmpq_div(&mut self.value, &self.value, &other.value) };
88    }
89}
90
91arithmetic_assign_trait_borrowed_to_owned!(DivAssign, div_assign, Q, Q);
92arithmetic_assign_trait_borrowed_to_owned!(DivAssign, div_assign, Q, Z);
93arithmetic_assign_between_types!(DivAssign, div_assign, Q, i64, i32 i16 i8);
94arithmetic_assign_between_types!(DivAssign, div_assign, Q, u64, u32 u16 u8);
95arithmetic_assign_between_types!(DivAssign, div_assign, Q, f64, f32);
96
97impl Div for &Q {
98    type Output = Q;
99    /// Implements the [`Div`] trait for two [`Q`] values.
100    /// [`Div`] is implemented for any combination of [`Q`] and borrowed [`Q`].
101    ///
102    /// Parameters:
103    /// - `other`: specifies the value `self` is divided by.
104    ///
105    /// Returns the result ot the division as a [`Q`].
106    ///
107    /// # Examples
108    /// ```
109    /// use qfall_math::rational::Q;
110    /// use std::str::FromStr;
111    ///
112    /// let a: Q = Q::from(42);
113    /// let b: Q = Q::from(24);
114    ///
115    /// let c: Q = &a / &b;
116    /// let d: Q = a / b;
117    /// let e: Q = &c / d;
118    /// let f: Q = c / &e;
119    /// ```
120    ///
121    /// # Panics ...
122    /// - if the `other` value is `0`.
123    fn div(self, other: Self) -> Self::Output {
124        self.div_safe(other).unwrap()
125    }
126}
127
128arithmetic_trait_borrowed_to_owned!(Div, div, Q, Q, Q);
129arithmetic_trait_mixed_borrowed_owned!(Div, div, Q, Q, Q);
130arithmetic_between_types!(Div, div, Q, Q, i64 i32 i16 i8 u64 u32 u16 u8 f32 f64);
131
132impl Div<&Z> for &Q {
133    type Output = Q;
134
135    /// Implements the [`Div`] trait for [`Q`] and [`Z`] values.
136    /// [`Div`] is implemented for any combination of owned and borrowed values.
137    ///
138    /// Parameters:
139    ///  - `other`: specifies the value to divide `self` by
140    ///
141    /// Returns the ratio of both numbers as a [`Q`].
142    ///
143    /// # Examples
144    /// ```
145    /// use qfall_math::rational::Q;
146    /// use qfall_math::integer::Z;
147    /// use std::str::FromStr;
148    ///
149    /// let a: Q = Q::from((42, 19));
150    /// let b: Z = Z::from(-42);
151    ///
152    /// let c: Q = &a / &b;
153    /// let d: Q = a / b;
154    /// let e: Q = &c / Z::from(42);
155    /// let f: Q = c / &Z::from(42);
156    /// ```
157    fn div(self, other: &Z) -> Self::Output {
158        assert!(!other.is_zero(), "Tried to divide {self} by zero.");
159
160        let mut out = Q::default();
161        unsafe {
162            fmpq_div_fmpz(&mut out.value, &self.value, &other.value);
163        }
164        out
165    }
166}
167
168arithmetic_trait_borrowed_to_owned!(Div, div, Q, Z, Q);
169arithmetic_trait_mixed_borrowed_owned!(Div, div, Q, Z, Q);
170
171impl Q {
172    /// Implements division for two borrowed [`Q`] values.
173    ///
174    /// Parameters:
175    /// - `divisor`: specifies the value `self` is divided by.
176    ///
177    /// Returns the result ot the division as a [`Q`] or an error if division by zero occurs.
178    ///
179    /// # Examples
180    /// ```
181    /// use qfall_math::rational::Q;
182    /// use std::str::FromStr;
183    ///
184    /// let a: Q = Q::from(42);
185    /// let b: Q = Q::from(24);
186    ///
187    /// let c: Q = a.div_safe(&b).unwrap();
188    /// ```
189    ///
190    ///  # Errors
191    /// - Returns a [`MathError`] of type [`MathError::DivisionByZeroError`] if
192    ///   the `divisor` is `0`.
193    pub fn div_safe(&self, divisor: &Q) -> Result<Q, MathError> {
194        if 0 != unsafe { fmpq_is_zero(&divisor.value) } {
195            return Err(MathError::DivisionByZeroError(format!(
196                "tried to divide Q with value {self} by Q with value {divisor}"
197            )));
198        }
199        let mut out = Q::default();
200        unsafe {
201            fmpq_div(&mut out.value, &self.value, &divisor.value);
202        }
203        Ok(out)
204    }
205}
206
207#[cfg(test)]
208mod test_div_assign {
209    use crate::{integer::Z, rational::Q};
210
211    /// Ensure that `div_assign` works for small numbers.
212    #[test]
213    fn correct_small() {
214        let mut a = Q::from(2);
215        let b = Q::from((42, 2));
216
217        a /= b;
218
219        assert_eq!(a, Q::from((4, 42)));
220    }
221
222    /// Ensure that `div_assign` works for large numbers.
223    #[test]
224    fn correct_large() {
225        let mut a = Q::from(u64::MAX - 1);
226        let b = Q::from(2);
227        let mut c = Q::from((1, i32::MAX));
228        let d = Q::from((1, u32::MAX));
229
230        a /= &b;
231        c /= d;
232
233        assert_eq!(a, Q::from(i64::MAX));
234        assert_eq!(c, Q::from((u32::MAX, (u32::MAX - 1) / 2)));
235    }
236
237    /// Ensure that `div_assign` is available for all types.
238    #[test]
239    fn availability() {
240        let mut a = Q::from((1, 2));
241        let b = Q::from((4, 5));
242        let c = Z::ONE;
243
244        a /= &b;
245        a /= b;
246        a /= &c;
247        a /= c;
248        a /= 0.5_f64;
249        a /= 0.5_f32;
250        a /= 1_u8;
251        a /= 1_u16;
252        a /= 1_u32;
253        a /= 1_u64;
254        a /= 1_i8;
255        a /= 1_i16;
256        a /= 1_i32;
257        a /= 1_i64;
258    }
259
260    /// Testing division by `0` panics
261    #[test]
262    #[should_panic]
263    fn div_by_zero() {
264        let mut a = Q::from((2, 3));
265        let b = 0;
266
267        a /= b;
268    }
269}
270
271#[cfg(test)]
272mod test_div {
273    use super::Q;
274
275    /// Testing division for two [`Q`]
276    #[test]
277    fn div() {
278        let a: Q = Q::from(2);
279        let b: Q = Q::from((42, 2));
280        let c: Q = a / b;
281        assert_eq!(c, Q::from((4, 42)));
282    }
283
284    /// Testing division for two borrowed [`Q`]
285    #[test]
286    fn div_borrow() {
287        let a: Q = Q::from(2);
288        let b: Q = Q::from((42, 2));
289        let c: Q = &a / &b;
290        assert_eq!(c, Q::from((4, 42)));
291    }
292
293    /// Testing division for borrowed [`Q`] and [`Q`]
294    #[test]
295    fn div_first_borrowed() {
296        let a: Q = Q::from(4);
297        let b: Q = Q::from((42, 10));
298        let c: Q = &a / b;
299        assert_eq!(c, Q::from((40, 42)));
300    }
301
302    /// Testing division for [`Q`] and borrowed [`Q`]
303    #[test]
304    fn div_second_borrowed() {
305        let a: Q = Q::from(2);
306        let b: Q = Q::from((42, 2));
307        let c: Q = a / &b;
308        assert_eq!(c, Q::from((4, 42)));
309    }
310
311    /// Testing division for large numerators and divisors
312    #[test]
313    fn div_large() {
314        let a: Q = Q::from(u64::MAX - 1);
315        let b: Q = Q::from(2);
316        let c: Q = Q::from((1, i32::MAX));
317        let d: Q = Q::from((1, u32::MAX));
318
319        let e: Q = &a / &b;
320        let f: Q = c / d;
321
322        assert_eq!(e, Q::from(i64::MAX));
323        assert_eq!(f, Q::from((u32::MAX, (u32::MAX - 1) / 2)));
324    }
325
326    /// Testing division by `0` panics
327    #[test]
328    #[should_panic]
329    fn div_by_zero() {
330        let a: Q = Q::from(2);
331        let b: Q = Q::ZERO;
332        let _c = a / b;
333    }
334
335    /// Testing division by `0` throws an error
336    #[test]
337    fn div_by_zero_safe() {
338        let a: Q = Q::from(2);
339        let b: Q = Q::ZERO;
340        assert!(&a.div_safe(&b).is_err());
341    }
342}
343
344#[cfg(test)]
345mod test_div_between_q_and_z {
346    use crate::integer::Z;
347    use crate::rational::Q;
348
349    /// Testing division for [`Q`] and [`Z`]
350    #[test]
351    fn div() {
352        let a: Q = Q::from((5, 7));
353        let b: Z = Z::from(4);
354        let c: Q = a / b;
355        assert_eq!(c, Q::from((5, 28)));
356    }
357
358    /// Testing division for both borrowed [`Q`] and [`Z`]
359    #[test]
360    fn div_borrow() {
361        let a: Q = Q::from((5, 7));
362        let b: Z = Z::from(4);
363        let c: Q = &a / &b;
364        assert_eq!(c, Q::from((5, 28)));
365    }
366
367    /// Testing division for borrowed [`Q`] and [`Z`]
368    #[test]
369    fn div_first_borrowed() {
370        let a: Q = Q::from((5, 7));
371        let b: Z = Z::from(4);
372        let c: Q = &a / b;
373        assert_eq!(c, Q::from((5, 28)));
374    }
375
376    /// Testing division for [`Q`] and borrowed [`Z`]
377    #[test]
378    fn div_second_borrowed() {
379        let a: Q = Q::from((5, 7));
380        let b: Z = Z::from(4);
381        let c: Q = a / &b;
382        assert_eq!(c, Q::from((5, 28)));
383    }
384
385    /// Testing division for large numbers
386    #[test]
387    fn div_large_numbers() {
388        let a: Q = Q::from((u64::MAX, 2));
389        let b: Q = Q::from((1, u64::MAX));
390        let c: Z = Z::from(u64::MAX);
391
392        let d: Q = a / &c;
393        let e: Q = b / c;
394
395        assert_eq!(d, Q::from((u64::MAX, 2)) / Q::from(u64::MAX));
396        assert_eq!(e, Q::from((1, u64::MAX)) / Q::from(u64::MAX));
397    }
398
399    /// Testing division by `0` panics
400    #[test]
401    #[should_panic]
402    fn div_by_zero() {
403        let a: Q = Q::from((2, 3));
404        let b: Z = Z::ZERO;
405        let _c = a / b;
406    }
407}
408
409#[cfg(test)]
410mod test_div_between_types {
411    use crate::rational::Q;
412
413    /// Testing division between different types
414    #[test]
415    #[allow(clippy::op_ref)]
416    fn div() {
417        let a: Q = Q::from(42);
418        let b: u64 = 1;
419        let c: u32 = 1;
420        let d: u16 = 1;
421        let e: u8 = 1;
422        let f: i64 = 1;
423        let g: i32 = 1;
424        let h: i16 = 1;
425        let i: i8 = 1;
426        let j: f32 = 0.3;
427        let k: f64 = 0.3;
428
429        let _: Q = &a / &b;
430        let _: Q = &a / &c;
431        let _: Q = &a / &d;
432        let _: Q = &a / &e;
433        let _: Q = &a / &f;
434        let _: Q = &a / &g;
435        let _: Q = &a / &h;
436        let _: Q = &a / &i;
437        let _: Q = &a / &j;
438        let _: Q = &a / &k;
439
440        let _: Q = &b / &a;
441        let _: Q = &c / &a;
442        let _: Q = &d / &a;
443        let _: Q = &e / &a;
444        let _: Q = &f / &a;
445        let _: Q = &g / &a;
446        let _: Q = &h / &a;
447        let _: Q = &i / &a;
448        let _: Q = &j / &a;
449        let _: Q = &k / &a;
450
451        let _: Q = &a / b;
452        let _: Q = &a / c;
453        let _: Q = &a / d;
454        let _: Q = &a / e;
455        let _: Q = &a / f;
456        let _: Q = &a / g;
457        let _: Q = &a / h;
458        let _: Q = &a / i;
459        let _: Q = &a / j;
460        let _: Q = &a / k;
461
462        let _: Q = &b / Q::from(42);
463        let _: Q = &c / Q::from(42);
464        let _: Q = &d / Q::from(42);
465        let _: Q = &e / Q::from(42);
466        let _: Q = &f / Q::from(42);
467        let _: Q = &g / Q::from(42);
468        let _: Q = &h / Q::from(42);
469        let _: Q = &i / Q::from(42);
470        let _: Q = &j / Q::from(42);
471        let _: Q = &k / Q::from(42);
472
473        let _: Q = Q::from(42) / &b;
474        let _: Q = Q::from(42) / &c;
475        let _: Q = Q::from(42) / &d;
476        let _: Q = Q::from(42) / &e;
477        let _: Q = Q::from(42) / &f;
478        let _: Q = Q::from(42) / &g;
479        let _: Q = Q::from(42) / &h;
480        let _: Q = Q::from(42) / &i;
481        let _: Q = Q::from(42) / &j;
482        let _: Q = Q::from(42) / &k;
483
484        let _: Q = b / &a;
485        let _: Q = c / &a;
486        let _: Q = d / &a;
487        let _: Q = e / &a;
488        let _: Q = f / &a;
489        let _: Q = g / &a;
490        let _: Q = h / &a;
491        let _: Q = i / &a;
492        let _: Q = j / &a;
493        let _: Q = k / &a;
494
495        let _: Q = Q::from(42) / b;
496        let _: Q = Q::from(42) / c;
497        let _: Q = Q::from(42) / d;
498        let _: Q = Q::from(42) / e;
499        let _: Q = Q::from(42) / f;
500        let _: Q = Q::from(42) / g;
501        let _: Q = Q::from(42) / h;
502        let _: Q = Q::from(42) / i;
503        let _: Q = Q::from(42) / j;
504        let _: Q = Q::from(42) / k;
505
506        let _: Q = b / Q::from(42);
507        let _: Q = c / Q::from(42);
508        let _: Q = d / Q::from(42);
509        let _: Q = e / Q::from(42);
510        let _: Q = f / Q::from(42);
511        let _: Q = g / Q::from(42);
512        let _: Q = h / Q::from(42);
513        let _: Q = i / Q::from(42);
514        let _: Q = j / Q::from(42);
515        let _: Q = k / Q::from(42);
516    }
517
518    /// Testing division by `0` panics
519    #[test]
520    #[should_panic]
521    fn div_by_zero_u64() {
522        let a: Q = Q::from(23);
523        let b: u64 = 0;
524        let _c = a / b;
525    }
526
527    /// Testing division by `0` panics
528    #[test]
529    #[should_panic]
530    fn div_by_zero_u32() {
531        let a: Q = Q::from(23);
532        let b: u32 = 0;
533        let _c = a / b;
534    }
535
536    /// Testing division by `0` panics
537    #[test]
538    #[should_panic]
539    fn div_by_zero_u16() {
540        let a: Q = Q::from(23);
541        let b: u16 = 0;
542        let _c = a / b;
543    }
544
545    /// Testing division by `0` panics
546    #[test]
547    #[should_panic]
548    fn div_by_zero_u8() {
549        let a: Q = Q::from(23);
550        let b: u8 = 0;
551        let _c = a / b;
552    }
553
554    /// Testing division by `0` panics
555    #[test]
556    #[should_panic]
557    fn div_by_zero_i64() {
558        let a: Q = Q::from(23);
559        let b: i64 = 0;
560        let _c = a / b;
561    }
562
563    /// Testing division by `0` panics
564    #[test]
565    #[should_panic]
566    fn div_by_zero_i32() {
567        let a: Q = Q::from(23);
568        let b: i32 = 0;
569        let _c = a / b;
570    }
571
572    /// Testing division by `0` panics
573    #[test]
574    #[should_panic]
575    fn div_by_zero_i16() {
576        let a: Q = Q::from(23);
577        let b: i16 = 0;
578        let _c = a / b;
579    }
580
581    /// Testing division by `0` panics
582    #[test]
583    #[should_panic]
584    fn div_by_zero_i8() {
585        let a: Q = Q::from(23);
586        let b: i8 = 0;
587        let _c = a / b;
588    }
589
590    /// Testing division by `0` panics
591    #[test]
592    #[should_panic]
593    fn div_by_zero_f32() {
594        let a: Q = Q::from(23);
595        let b: f32 = 0.0;
596        let _c = a / b;
597    }
598
599    /// Testing division by `0` panics
600    #[test]
601    #[should_panic]
602    fn div_by_zero_f64() {
603        let a: Q = Q::from(23);
604        let b: f64 = 0.0;
605        let _c = a / b;
606    }
607
608    /// Testing if division for different types returns the correct results.
609    #[test]
610    fn div_correct_i32() {
611        let a: i32 = 1;
612        let b: Q = Q::from(23);
613
614        let c = a / &b;
615        let d = &b / a;
616
617        assert_eq!(c, Q::from((1, 23)));
618        assert_eq!(d, Q::from(23));
619    }
620}