qfall_math/rational/q/arithmetic/
sub.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 [`Sub`] 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_sub, fmpq_sub_fmpz, fmpq_sub_si, fmpq_sub_ui};
21use std::ops::{Sub, SubAssign};
22
23impl SubAssign<&Q> for Q {
24    /// Computes the subtraction of `self` and `other` reusing
25    /// the memory of `self`.
26    /// [`SubAssign`] 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 subtract from `self`
31    ///
32    /// Returns the difference 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 sub_assign(&mut self, other: &Self) {
49        unsafe { fmpq_sub(&mut self.value, &self.value, &other.value) };
50    }
51}
52impl SubAssign<&Z> for Q {
53    /// Documentation at [`Q::sub_assign`].
54    fn sub_assign(&mut self, other: &Z) {
55        unsafe { fmpq_sub_fmpz(&mut self.value, &self.value, &other.value) };
56    }
57}
58impl SubAssign<i64> for Q {
59    /// Documentation at [`Q::sub_assign`].
60    fn sub_assign(&mut self, other: i64) {
61        unsafe { fmpq_sub_si(&mut self.value, &self.value, other) };
62    }
63}
64impl SubAssign<u64> for Q {
65    /// Documentation at [`Q::sub_assign`].
66    fn sub_assign(&mut self, other: u64) {
67        unsafe { fmpq_sub_ui(&mut self.value, &self.value, other) };
68    }
69}
70impl SubAssign<f64> for Q {
71    /// Documentation at [`Q::sub_assign`].
72    fn sub_assign(&mut self, other: f64) {
73        let other = Q::from(other);
74
75        unsafe { fmpq_sub(&mut self.value, &self.value, &other.value) };
76    }
77}
78
79arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, Q, Q);
80arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, Q, Z);
81arithmetic_assign_between_types!(SubAssign, sub_assign, Q, i64, i32 i16 i8);
82arithmetic_assign_between_types!(SubAssign, sub_assign, Q, u64, u32 u16 u8);
83arithmetic_assign_between_types!(SubAssign, sub_assign, Q, f64, f32);
84
85impl Sub for &Q {
86    type Output = Q;
87    /// Implements the [`Sub`] trait for two [`Q`] values.
88    /// [`Sub`] is implemented for any combination of [`Q`] and borrowed [`Q`].
89    ///
90    /// Parameters:
91    ///  - `other`: specifies the value to subtract from `self`
92    ///
93    /// Returns the result of the subtraction 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((-42, 2));
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 sub(self, other: Self) -> Self::Output {
109        let mut out = Q::default();
110        unsafe {
111            fmpq_sub(&mut out.value, &self.value, &other.value);
112        }
113        out
114    }
115}
116
117arithmetic_trait_borrowed_to_owned!(Sub, sub, Q, Q, Q);
118arithmetic_trait_mixed_borrowed_owned!(Sub, sub, Q, Q, Q);
119arithmetic_between_types!(Sub, sub, Q, Q, i64 i32 i16 i8 u64 u32 u16 u8 f32 f64);
120
121impl Sub<&Z> for &Q {
122    type Output = Q;
123
124    /// Implements the [`Sub`] trait for [`Q`] and [`Z`] values.
125    /// [`Sub`] is implemented for any combination of owned and borrowed values.
126    ///
127    /// Parameters:
128    ///  - `other`: specifies the value to subtract from `self`
129    ///
130    /// Returns the result of the subtraction 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 sub(self, other: &Z) -> Self::Output {
147        let mut out = Q::default();
148        unsafe {
149            fmpq_sub_fmpz(&mut out.value, &self.value, &other.value);
150        }
151        out
152    }
153}
154
155arithmetic_trait_borrowed_to_owned!(Sub, sub, Q, Z, Q);
156arithmetic_trait_mixed_borrowed_owned!(Sub, sub, Q, Z, Q);
157
158#[cfg(test)]
159mod test_sub_assign {
160    use crate::{integer::Z, rational::Q};
161
162    /// Ensure that `sub_assign` works for small numbers.
163    #[test]
164    fn correct_small() {
165        let mut a = Q::MINUS_ONE;
166        let b = Q::ONE;
167        let c = Q::MINUS_ONE;
168        let d = Q::from((-1, 2));
169
170        a -= &b;
171        assert_eq!(-2, a);
172        a -= &c;
173        assert_eq!(-1, a);
174        a -= &c;
175        assert_eq!(0, a);
176        a -= &c;
177        assert_eq!(1, a);
178        a -= &c;
179        assert_eq!(2, a);
180        a -= 2 * b;
181        assert_eq!(0, a);
182        a -= d;
183        assert_eq!(Q::from((1, 2)), a);
184    }
185
186    /// Ensure that `sub_assign` works for large numbers.
187    #[test]
188    fn correct_large() {
189        let mut a = Q::from(i64::MAX);
190        let b = -1 * Q::from(i64::MIN);
191        let c = -1 * Q::from(u64::MAX);
192
193        a -= b;
194        assert_eq!(-1, a);
195        a -= c;
196        assert_eq!(u64::MAX - 1, a);
197    }
198
199    /// Ensure that `sub_assign` is available for all types.
200    #[test]
201    fn availability() {
202        let mut a = Q::from((1, 2));
203        let b = Q::from((4, 5));
204        let c = Z::ONE;
205
206        a -= &b;
207        a -= b;
208        a -= &c;
209        a -= c;
210        a -= 0.5_f64;
211        a -= 0.5_f32;
212        a -= 1_u8;
213        a -= 1_u16;
214        a -= 1_u32;
215        a -= 1_u64;
216        a -= 1_i8;
217        a -= 1_i16;
218        a -= 1_i32;
219        a -= 1_i64;
220    }
221}
222
223#[cfg(test)]
224mod test_sub {
225    use super::Q;
226
227    /// Testing subtraction for two [`Q`]
228    #[test]
229    fn sub() {
230        let a: Q = Q::from(42);
231        let b: Q = Q::from((42, 2));
232        let c: Q = a - b;
233        assert_eq!(c, Q::from(21));
234    }
235
236    /// Testing subtraction for two borrowed [`Q`]
237    #[test]
238    fn sub_borrow() {
239        let a: Q = Q::from(42);
240        let b: Q = Q::from((42, 2));
241        let c: Q = &a - &b;
242        assert_eq!(c, Q::from(21));
243    }
244
245    /// Testing subtraction for borrowed [`Q`] and [`Q`]
246    #[test]
247    fn sub_first_borrowed() {
248        let a: Q = Q::from((42, 5));
249        let b: Q = Q::from((42, 10));
250        let c: Q = &a - b;
251        assert_eq!(c, Q::from((21, 5)));
252    }
253
254    /// Testing subtraction for [`Q`] and borrowed [`Q`]
255    #[test]
256    fn sub_second_borrowed() {
257        let a: Q = Q::from(42);
258        let b: Q = Q::from((42, 2));
259        let c: Q = a - &b;
260        assert_eq!(c, Q::from(21));
261    }
262
263    /// Testing subtraction for large numerators and divisors
264    #[test]
265    fn sub_large() {
266        let a: Q = Q::from(i64::MAX);
267        let b: Q = Q::from(u64::MAX - 1);
268        let c: Q = Q::from((1, i64::MAX));
269        let d: Q = Q::from((1, u64::MAX));
270        let e: Q = &b - &a;
271        let f: Q = &c - &d;
272        assert_eq!(e, a);
273        assert_eq!(f, Q::from((-1, u64::MAX)) + Q::from((1, i64::MAX)));
274    }
275}
276
277#[cfg(test)]
278mod test_sub_between_z_and_q {
279    use super::Z;
280    use crate::rational::Q;
281
282    /// Testing subtraction for [`Q`] and [`Z`]
283    #[test]
284    fn sub() {
285        let a: Q = Q::from((5, 7));
286        let b: Z = Z::from(4);
287        let c: Q = a - b;
288        assert_eq!(c, Q::from((-23, 7)));
289    }
290
291    /// Testing subtraction for both borrowed [`Q`] and [`Z`]
292    #[test]
293    fn sub_borrow() {
294        let a: Q = Q::from((5, 7));
295        let b: Z = Z::from(4);
296        let c: Q = &a - &b;
297        assert_eq!(c, Q::from((-23, 7)));
298    }
299
300    /// Testing subtraction for borrowed [`Q`] and [`Z`]
301    #[test]
302    fn sub_first_borrowed() {
303        let a: Q = Q::from((5, 7));
304        let b: Z = Z::from(4);
305        let c: Q = &a - b;
306        assert_eq!(c, Q::from((-23, 7)));
307    }
308
309    /// Testing subtraction for [`Q`] and borrowed [`Z`]
310    #[test]
311    fn sub_second_borrowed() {
312        let a: Q = Q::from((5, 7));
313        let b: Z = Z::from(4);
314        let c: Q = a - &b;
315        assert_eq!(c, Q::from((-23, 7)));
316    }
317
318    /// Testing subtraction for large numbers
319    #[test]
320    fn sub_large_numbers() {
321        let a: Q = Q::from((u64::MAX, 2));
322        let b: Q = Q::from((1, u64::MAX));
323        let c: Z = Z::from(u64::MAX);
324        let d: Q = a - &c;
325        let e: Q = b - c;
326        assert_eq!(d, Q::from((u64::MAX, 2)) - Q::from(u64::MAX));
327        assert_eq!(e, Q::from((1, u64::MAX)) - Q::from(u64::MAX));
328    }
329}
330
331#[cfg(test)]
332mod test_sub_between_types {
333    use crate::rational::Q;
334
335    /// Testing subtraction between different types
336    #[test]
337    #[allow(clippy::op_ref)]
338    fn sub() {
339        let a: Q = Q::from(42);
340        let b: u64 = 1;
341        let c: u32 = 1;
342        let d: u16 = 1;
343        let e: u8 = 1;
344        let f: i64 = 1;
345        let g: i32 = 1;
346        let h: i16 = 1;
347        let i: i8 = 1;
348        let j: f32 = 1.3;
349        let k: f64 = 1.3;
350
351        let _: Q = &a - &b;
352        let _: Q = &a - &c;
353        let _: Q = &a - &d;
354        let _: Q = &a - &e;
355        let _: Q = &a - &f;
356        let _: Q = &a - &g;
357        let _: Q = &a - &h;
358        let _: Q = &a - &i;
359        let _: Q = &a - &j;
360        let _: Q = &a - &k;
361
362        let _: Q = &b - &a;
363        let _: Q = &c - &a;
364        let _: Q = &d - &a;
365        let _: Q = &e - &a;
366        let _: Q = &f - &a;
367        let _: Q = &g - &a;
368        let _: Q = &h - &a;
369        let _: Q = &i - &a;
370        let _: Q = &j - &a;
371        let _: Q = &k - &a;
372
373        let _: Q = &a - b;
374        let _: Q = &a - c;
375        let _: Q = &a - d;
376        let _: Q = &a - e;
377        let _: Q = &a - f;
378        let _: Q = &a - g;
379        let _: Q = &a - h;
380        let _: Q = &a - i;
381        let _: Q = &a - j;
382        let _: Q = &a - k;
383
384        let _: Q = &b - Q::from(42);
385        let _: Q = &c - Q::from(42);
386        let _: Q = &d - Q::from(42);
387        let _: Q = &e - Q::from(42);
388        let _: Q = &f - Q::from(42);
389        let _: Q = &g - Q::from(42);
390        let _: Q = &h - Q::from(42);
391        let _: Q = &i - Q::from(42);
392        let _: Q = &j - Q::from(42);
393        let _: Q = &k - Q::from(42);
394
395        let _: Q = Q::from(42) - &b;
396        let _: Q = Q::from(42) - &c;
397        let _: Q = Q::from(42) - &d;
398        let _: Q = Q::from(42) - &e;
399        let _: Q = Q::from(42) - &f;
400        let _: Q = Q::from(42) - &g;
401        let _: Q = Q::from(42) - &h;
402        let _: Q = Q::from(42) - &i;
403        let _: Q = Q::from(42) - &j;
404        let _: Q = Q::from(42) - &k;
405
406        let _: Q = b - &a;
407        let _: Q = c - &a;
408        let _: Q = d - &a;
409        let _: Q = e - &a;
410        let _: Q = f - &a;
411        let _: Q = g - &a;
412        let _: Q = h - &a;
413        let _: Q = i - &a;
414        let _: Q = j - &a;
415        let _: Q = k - &a;
416
417        let _: Q = Q::from(42) - b;
418        let _: Q = Q::from(42) - c;
419        let _: Q = Q::from(42) - d;
420        let _: Q = Q::from(42) - e;
421        let _: Q = Q::from(42) - f;
422        let _: Q = Q::from(42) - g;
423        let _: Q = Q::from(42) - h;
424        let _: Q = Q::from(42) - i;
425        let _: Q = Q::from(42) - j;
426        let _: Q = Q::from(42) - k;
427
428        let _: Q = b - Q::from(42);
429        let _: Q = c - Q::from(42);
430        let _: Q = d - Q::from(42);
431        let _: Q = e - Q::from(42);
432        let _: Q = f - Q::from(42);
433        let _: Q = g - Q::from(42);
434        let _: Q = h - Q::from(42);
435        let _: Q = i - Q::from(42);
436        let _: Q = j - Q::from(42);
437        let _: Q = k - Q::from(42);
438    }
439}