qfall_math/rational/q/
cmp.rs

1// Copyright © 2023 Sven Moog, Niklas Siemer, Marcel Luca Schmidt
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//! Implementations to compare [`Q`] with other values.
10//! This uses the traits from [`std::cmp`].
11
12use super::Q;
13use crate::{
14    integer::Z,
15    integer_mod_q::Modulus,
16    macros::for_others::{implement_for_others, implement_trait_reverse},
17};
18use flint_sys::{
19    fmpq::{fmpq_cmp, fmpq_equal},
20    fmpz::{fmpz, fmpz_equal},
21};
22use std::cmp::Ordering;
23
24impl PartialEq for Q {
25    /// Checks if two rationals are equal. Used by the `==` and `!=` operators.
26    ///
27    /// Parameters:
28    /// - `other`: the other value that is used to compare the elements
29    ///
30    /// Returns `true` if the elements are equal, otherwise `false`.
31    ///
32    /// # Examples
33    /// ```
34    /// use qfall_math::rational::Q;
35    /// use std::str::FromStr;
36    /// let a: Q = Q::from((42, 24));
37    /// let b: Q = Q::from((24, 42));
38    ///
39    /// // These are all equivalent and return false.
40    /// let compared: bool = (a == b);
41    /// # assert!(!compared);
42    /// let compared: bool = (&a == &b);
43    /// # assert!(!compared);
44    /// let compared: bool = (a.eq(&b));
45    /// # assert!(!compared);
46    /// let compared: bool = (Q::eq(&a, &b));
47    /// # assert!(!compared);
48    /// ```
49    fn eq(&self, other: &Self) -> bool {
50        unsafe { 1 == fmpq_equal(&self.value, &other.value) }
51    }
52}
53
54// With the [`Eq`] trait, `a == a` is always true.
55// This is not guaranteed by the [`PartialEq`] trait.
56// We do not allow division by zero, therefore, this is the case.
57impl Eq for Q {}
58
59impl PartialEq<Z> for Q {
60    /// Checks if an integer and a rational are equal. Used by the `==` and `!=` operators.
61    /// [`PartialEq`] is also implemented for [`Z`] using [`Q`].
62    ///
63    /// Parameters:
64    /// - `other`: the other value that is used to compare the elements
65    ///
66    /// Returns `true` if the elements are equal, otherwise `false`.
67    ///
68    /// # Examples
69    /// ```
70    /// use qfall_math::integer::Z;
71    /// use qfall_math::rational::Q;
72    /// let a: Q = Q::from(42);
73    /// let b: Z = Z::from(42);
74    ///
75    /// // These are all equivalent and return true.
76    /// let compared: bool = (a == b);
77    /// # assert!(compared);
78    /// let compared: bool = (b == a);
79    /// # assert!(compared);
80    /// let compared: bool = (&a == &b);
81    /// # assert!(compared);
82    /// let compared: bool = (&b == &a);
83    /// # assert!(compared);
84    /// let compared: bool = (a.eq(&b));
85    /// # assert!(compared);
86    /// let compared: bool = (b.eq(&a));
87    /// # assert!(compared);
88    /// let compared: bool = (Q::eq(&a, &b));
89    /// # assert!(compared);
90    /// let compared: bool = (Z::eq(&b, &a));
91    /// # assert!(compared);
92    /// ```
93    fn eq(&self, other: &Z) -> bool {
94        unsafe {
95            (1 == fmpz_equal(&self.value.den, &fmpz(1)))
96                && (1 == fmpz_equal(&self.value.num, &other.value))
97        }
98    }
99}
100
101implement_trait_reverse!(PartialEq, eq, Z, Q, bool);
102
103impl PartialEq<Modulus> for Q {
104    /// Checks if an integer and a rational are equal. Used by the `==` and `!=` operators.
105    /// [`PartialEq`] is also implemented for [`Modulus`] using [`Q`].
106    ///
107    /// Parameters:
108    /// - `other`: the other value that is used to compare the elements
109    ///
110    /// Returns `true` if the elements are equal, otherwise `false`.
111    ///
112    /// # Examples
113    /// ```
114    /// use qfall_math::integer_mod_q::Modulus;
115    /// use qfall_math::rational::Q;
116    /// let a: Q = Q::from(42);
117    /// let b: Modulus = Modulus::from(42);
118    ///
119    /// // These are all equivalent and return true.
120    /// let compared: bool = (a == b);
121    /// # assert!(compared);
122    /// let compared: bool = (b == a);
123    /// # assert!(compared);
124    /// let compared: bool = (&a == &b);
125    /// # assert!(compared);
126    /// let compared: bool = (&b == &a);
127    /// # assert!(compared);
128    /// let compared: bool = (a.eq(&b));
129    /// # assert!(compared);
130    /// let compared: bool = (b.eq(&a));
131    /// # assert!(compared);
132    /// let compared: bool = (Q::eq(&a, &b));
133    /// # assert!(compared);
134    /// let compared: bool = (Modulus::eq(&b, &a));
135    /// # assert!(compared);
136    /// ```
137    fn eq(&self, other: &Modulus) -> bool {
138        unsafe {
139            (1 == fmpz_equal(&self.value.den, &fmpz(1)))
140                && (1 == fmpz_equal(&self.value.num, &other.modulus.n[0]))
141        }
142    }
143}
144
145implement_trait_reverse!(PartialEq, eq, Modulus, Q, bool);
146
147implement_for_others!(Z, Q, PartialEq for fmpz i8 i16 i32 i64 u8 u16 u32 u64);
148
149impl PartialOrd for Q {
150    /// Compares two [`Q`] values. Used by the `<`, `<=`, `>`, and `>=` operators.
151    ///
152    /// Parameters:
153    /// - `other`: the other value that is used to compare the elements
154    ///
155    /// Returns the [`Ordering`] of the elements.
156    ///
157    /// # Examples
158    /// ```
159    /// # use qfall_math::error::MathError;
160    /// use qfall_math::rational::Q;
161    ///
162    /// let a: Q = Q::from((1, 10));
163    /// let b: Q = Q::from((2, 10));
164    ///
165    /// assert!(a < b);
166    /// assert!(a <= b);
167    /// assert!(b > a);
168    /// assert!(b >= a);
169    ///
170    /// assert!(&a < &b);
171    /// # Ok::<(), MathError>(())
172    /// ```
173    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
174        Some(self.cmp(other))
175    }
176}
177
178impl Ord for Q {
179    //! Enables the usage of `max`, `min`, and `clamp`.
180    //!
181    //! # Examples
182    //! ```
183    //! use qfall_math::rational::Q;
184    //! use std::cmp::{max, min};
185    //!
186    //! let a: Q = Q::from(10);
187    //! let b: Q = Q::from(42);
188    //!
189    //! assert_eq!(b, max(a.clone(), b.clone()));
190    //! assert_eq!(a, min(a.clone(), b.clone()));
191    //! assert_eq!(a, Q::ZERO.clamp(a.clone(), b.clone()));
192    //! ```
193
194    /// Compares two [`Q`] values. Used by the `<`, `<=`, `>`, and `>=` operators.
195    ///
196    /// Parameters:
197    /// - `other`: the other value that is used to compare the elements
198    ///
199    /// Returns the [`Ordering`] of the elements.
200    ///
201    /// # Examples
202    /// ```
203    /// use qfall_math::rational::Q;
204    ///
205    /// let a: Q = Q::from(10);
206    /// let b: Q = Q::from(42);
207    ///
208    /// assert!(a < b);
209    /// assert!(a <= b);
210    /// assert!(b > a);
211    /// assert!(b >= a);
212    /// ```
213    fn cmp(&self, other: &Self) -> Ordering {
214        unsafe { fmpq_cmp(&self.value, &other.value).cmp(&0) }
215    }
216}
217
218implement_for_others!(Q, Q, PartialOrd for Modulus Z fmpz i8 i16 i32 i64 u8 u16 u32 u64);
219
220/// Test that the [`PartialEq`] trait is correctly implemented.
221#[cfg(test)]
222mod test_partial_eq_q {
223    /// Test case structure:
224    /// 1. Different ways to use equal and not equal.
225    /// 2. Test different combinations of equal and not equal with different
226    ///    parameter length combinations.
227    ///    Not equal test are inverted equal tests.
228    use super::Q;
229    use std::str::FromStr;
230
231    // Ensure that the function can be called between owned and borrowed values
232    #[test]
233    #[allow(clippy::op_ref)]
234    fn availability() {
235        let q = Q::ONE;
236
237        assert!(q == q);
238        assert!(&q == &q);
239    }
240
241    /// Demonstrate the different ways to use equal.
242    /// We assume that they behave the same in the other tests.
243    #[test]
244    #[allow(clippy::op_ref)]
245    fn equal_call_methods() {
246        let one_1 = Q::ONE;
247        let one_2 = Q::ONE;
248
249        assert!(one_1 == one_2);
250        assert!(&one_1 == &one_2);
251        assert!(one_1.eq(&one_2));
252        assert!(Q::eq(&one_1, &one_2));
253        assert_eq!(one_1, one_2);
254    }
255
256    /// Demonstrate the different ways to use not equal.
257    /// We assume that they behave the same in the other tests.
258    #[test]
259    #[allow(clippy::op_ref)]
260    fn not_equal_call_methods() {
261        let one = Q::ONE;
262        let two = Q::from(2);
263
264        assert!(one != two);
265        assert!(&one != &two);
266        assert!(one.ne(&two));
267        assert!(Q::ne(&one, &two));
268        assert_ne!(one, two);
269    }
270
271    /// Test equal with small positive and negative numbers.
272    #[test]
273    fn equal_small() {
274        let small_1 = Q::from(10);
275        let small_2 = Q::from(10);
276
277        assert!(small_1 == small_2);
278        assert!(small_2 == small_1);
279        assert!(small_1 == small_1);
280    }
281
282    /// Test not equal with small positive and negative numbers.
283    #[test]
284    fn not_equal_small() {
285        let small_1 = Q::from(10);
286        let negative = Q::MINUS_ONE;
287
288        assert!(small_1 != negative);
289        assert!(negative != small_1);
290    }
291
292    /// Test equal with a large [`Q`]
293    /// (uses FLINT's pointer representation)
294    #[test]
295    fn equal_large() {
296        let max_1 = Q::from_str(&"1".repeat(65)).unwrap();
297        let max_2 = Q::from_str(&"1".repeat(65)).unwrap();
298        let large_negative_str = format!("-{:1<65}", "1");
299        let min = Q::from_str(&large_negative_str).unwrap();
300
301        assert!(max_1 == max_2);
302        assert!(max_2 == max_1);
303        assert!(max_1 == max_1);
304        assert!(min == min);
305    }
306
307    /// Test not equal with a large [`Q`]
308    /// (uses FLINT's pointer representation)
309    #[test]
310    fn not_equal_large() {
311        let max_1 = Q::from_str(&"1".repeat(65)).unwrap();
312        let large_negative_str = format!("-{:1<65}", "1");
313        let min = Q::from_str(&large_negative_str).unwrap();
314
315        assert!(max_1 != min);
316        assert!(min != max_1);
317    }
318
319    /// Test not equal with a large [`Q`] (uses FLINT's pointer representation)
320    /// and small [`Q`] (no pointer representation).
321    #[test]
322    fn not_equal_large_small() {
323        let max = Q::from_str(&"1".repeat(65)).unwrap();
324        let small_positive = Q::ONE;
325        let small_negative = Q::MINUS_ONE;
326        let large_negative_str = format!("-{:1<65}", "1");
327        let min = Q::from_str(&large_negative_str).unwrap();
328
329        assert!(max != small_negative);
330        assert!(small_negative != max);
331        assert!(max != small_positive);
332        assert!(small_positive != max);
333
334        assert!(min != small_negative);
335        assert!(small_negative != min);
336        assert!(min != small_positive);
337        assert!(small_positive != min);
338    }
339
340    /// Test equal with small [`Q`] that have a large denominator
341    /// (uses FLINT's pointer representation)
342    #[test]
343    fn equal_large_denominator() {
344        let large_denominator_str = format!("1/{:1<200}", "1");
345        let large_denominator_less_str = format!("1/{:1<201}", "1");
346
347        let small_1 = Q::from_str(&large_denominator_str).unwrap();
348        let small_2 = Q::from_str(&large_denominator_str).unwrap();
349        let less = Q::from_str(&large_denominator_less_str).unwrap();
350
351        assert!(small_1 == small_2);
352        assert!(small_2 == small_1);
353        assert!(small_1 == small_1);
354
355        assert!(less == less);
356    }
357
358    /// Test equal for [`Q`] with large numerator and denominator
359    /// (uses FLINT's pointer representation)
360    #[test]
361    fn equal_large_numerator_denominator() {
362        // The greatest common divisor of numerator and denominator is 1
363        // => also large after canonicalization
364        let large_denominator_str = format!("{:5<200}/{:4<200}", "1", "1");
365        let large_denominator_less_str = format!("{:5<201}/{:4<201}", "1", "1");
366
367        let small_1 = Q::from_str(&large_denominator_str).unwrap();
368        let small_2 = Q::from_str(&large_denominator_str).unwrap();
369        let less = Q::from_str(&large_denominator_less_str).unwrap();
370
371        assert!(small_1 == small_2);
372        assert!(small_2 == small_1);
373        assert!(small_1 == small_1);
374
375        assert!(less == less);
376    }
377
378    /// Ensure that two elements are equal
379    #[test]
380    fn equal_rational() {
381        let a = Q::from((1, 2));
382        let b = Q::from((2, 4));
383
384        assert_eq!(a, b);
385    }
386
387    /// assert not equal when denominator is different
388    #[test]
389    fn not_equal_different_denominator() {
390        let a = Q::from((1, 2));
391        let b = Q::from((1, 4));
392
393        assert_ne!(a, b);
394    }
395
396    /// assert equal for `0` when denominator is different
397    #[test]
398    fn zero_equal_different_denominator() {
399        let a = Q::from((0, 2));
400        let b = Q::from((0, 4));
401
402        assert_eq!(a, b);
403    }
404}
405
406/// Test that the [`PartialEq`] trait is correctly implemented.
407#[cfg(test)]
408mod test_partial_eq_q_other {
409    use super::Q;
410    use crate::{integer::Z, integer_mod_q::Modulus};
411
412    // Ensure that the function can be called with several types
413    #[test]
414    #[allow(clippy::op_ref)]
415    fn availability() {
416        let q = Q::from((2, 1));
417        let z = Z::from(2);
418        let modulus = Modulus::from(2);
419
420        assert!(q == z);
421        assert!(q == modulus);
422        assert!(q == z.value);
423        assert!(q == 2i8);
424        assert!(q == 2u8);
425        assert!(q == 2i16);
426        assert!(q == 2u16);
427        assert!(q == 2i32);
428        assert!(q == 2u32);
429        assert!(q == 2i64);
430        assert!(q == 2u64);
431
432        assert!(z == q);
433        assert!(modulus == q);
434        assert!(z.value == q);
435        assert!(2i8 == q);
436        assert!(2u8 == q);
437        assert!(2i16 == q);
438        assert!(2u16 == q);
439        assert!(2i32 == q);
440        assert!(2u32 == q);
441        assert!(2i64 == q);
442        assert!(2u64 == q);
443
444        assert!(&q == &z);
445        assert!(&z == &q);
446        assert!(&q == &modulus);
447        assert!(&modulus == &q);
448        assert!(&q == &2i8);
449        assert!(&2i8 == &q);
450    }
451
452    // Ensure that large values are compared correctly
453    #[test]
454    fn equal_large() {
455        let q = Q::from((u64::MAX, 1));
456        let z = Z::from(u64::MAX);
457        let modulus1 = Modulus::from(u64::MAX);
458        let modulus2 = Modulus::from(u64::MAX - 1);
459
460        assert!(q == z);
461        assert!(q == modulus1);
462        assert!(q != z + 1);
463        assert!(q != modulus2);
464    }
465}
466
467/// Test the [`PartialOrd`] trait implementation for [`Q`]
468#[cfg(test)]
469#[allow(clippy::neg_cmp_op_on_partial_ord)]
470mod test_partial_ord {
471    use super::Q;
472
473    /// Different ways to compare [`Q`] elements with each other
474    #[test]
475    fn call_methods() {
476        let one = Q::ONE;
477        let zero = Q::ZERO;
478
479        assert!(one >= zero);
480        assert!(one > zero);
481    }
482
483    /// Test less (<) comparison between small positive and negative [`Q`]
484    /// (FLINT is not using pointers)
485    #[test]
486    fn less_small() {
487        let one_1 = Q::ONE;
488        let small_negative = Q::MINUS_ONE;
489        let one_half = Q::from((1, 2));
490
491        assert!(small_negative < one_1);
492
493        assert!(one_half < one_1);
494        assert!(small_negative < one_half);
495    }
496
497    /// Test less (<) comparison between large [`Q`] (FLINT uses pointers)
498    /// and small [`Q`] (not using pointers).
499    #[test]
500    fn less_large_small() {
501        let large = Q::from((u64::MAX, 2));
502        let small_positive = Q::ONE;
503        let small_negative = Q::from((i64::MIN + 1, i64::MAX));
504        let large_negative = Q::from(i64::MIN);
505
506        // Comparisons with max
507        assert!(small_positive < large);
508        assert!(small_negative < large);
509
510        // Comparisons with max_negative
511        assert!(large_negative < small_positive);
512        assert!(large_negative < small_negative);
513    }
514
515    /// Test less (<) comparison between large positive and negative [`Q`]
516    /// (FLINT uses pointers)
517    #[test]
518    fn less_large() {
519        let max_1 = Q::from(u64::MAX);
520        let max_negative = Q::from(i64::MIN);
521
522        assert!(max_negative < max_1);
523    }
524
525    /// Test less or equal (<=) comparison between small positive and negative [`Q`]
526    /// (FLINT is not using pointers)
527    #[test]
528    fn less_equal_small() {
529        let small_positive_1 = Q::ONE;
530        let small_positive_2 = Q::ONE;
531        let small_negative = Q::MINUS_ONE;
532
533        assert!(small_positive_1 <= small_positive_2);
534        assert!(small_positive_2 <= small_positive_1);
535        assert!(small_positive_1 <= small_positive_1);
536
537        assert!(small_negative <= small_positive_1);
538        assert!(small_negative <= small_negative);
539    }
540
541    /// Test less or equal (<=) comparison between large [`Q`] (FLINT uses pointers)
542    /// and small [`Q`] (not using pointers).
543    #[test]
544    fn less_equal_large_small() {
545        let max = Q::from(u64::MAX);
546        let small_positive = Q::ONE;
547        let small_negative = Q::MINUS_ONE;
548        let max_negative = Q::from(i64::MIN);
549
550        // Comparisons with max
551        assert!(small_positive <= max);
552        assert!(small_negative <= max);
553
554        // Comparisons with max_negative
555        assert!(max_negative <= small_positive);
556        assert!(max_negative <= small_negative);
557    }
558
559    /// Test less or equal (<=) comparison between large positive and negative [`Q`]
560    /// (FLINT uses pointers)
561    #[test]
562    fn less_equal_large() {
563        let max_1 = Q::from(u64::MAX);
564        let max_2 = Q::from(u64::MAX);
565        let max_negative = Q::from(i64::MIN);
566
567        assert!(max_1 <= max_2);
568        assert!(max_2 <= max_1);
569        assert!(max_1 <= max_1);
570
571        assert!(max_negative <= max_1);
572        assert!(max_negative <= max_negative);
573    }
574
575    /// Test greater (>) comparison between small positive and negative [`Q`]
576    /// (FLINT is not using pointers)
577    #[test]
578    fn greater_small() {
579        let small_positive_1 = Q::ONE;
580        let small_negative = Q::MINUS_ONE;
581
582        assert!(small_positive_1 > small_negative);
583    }
584
585    /// Test greater (>) comparison between large [`Q`] (FLINT uses pointers)
586    /// and small [`Q`] (not using pointers).
587    #[test]
588    fn greater_large_small() {
589        let max = Q::from(u64::MAX);
590        let small_positive = Q::ONE;
591        let small_negative = Q::MINUS_ONE;
592        let max_negative = Q::from(i64::MIN);
593
594        // Comparisons with max
595        assert!(max > small_positive);
596        assert!(max > small_negative);
597
598        // Comparisons with max_negative
599        assert!(small_positive > max_negative);
600        assert!(small_negative > max_negative);
601    }
602
603    /// Test greater (>) comparison between large positive and negative [`Q`]
604    /// (FLINT uses pointers)
605    #[test]
606    fn greater_large() {
607        let max_1 = Q::from(u64::MAX);
608        let max_negative = Q::from(i64::MIN);
609
610        assert!(max_1 > max_negative);
611    }
612
613    /// Test greater or equal (>=) comparison between small positive and negative [`Q`]
614    /// (FLINT is not using pointers)
615    #[test]
616    fn greater_equal_small() {
617        let small_positive_1 = Q::ONE;
618        let small_positive_2 = Q::ONE;
619        let small_negative = Q::MINUS_ONE;
620
621        assert!(small_positive_1 >= small_positive_2);
622        assert!(small_positive_2 >= small_positive_1);
623        assert!(small_positive_1 >= small_positive_1);
624
625        assert!(small_positive_1 >= small_negative);
626        assert!(small_negative >= small_negative);
627    }
628
629    /// Test greater or equal (>=) comparison between large [`Q`] (FLINT uses pointers)
630    /// and small [`Q`] (not using pointers).
631    #[test]
632    fn greater_equal_large_small() {
633        let max = Q::from(u64::MAX);
634        let small_positive = Q::ONE;
635        let small_negative = Q::MINUS_ONE;
636        let max_negative = Q::from(i64::MIN);
637
638        // Comparisons with max
639        assert!(max >= small_positive);
640        assert!(max >= small_negative);
641
642        // Comparisons with max_negative
643        assert!(small_positive >= max_negative);
644        assert!(small_negative >= max_negative);
645    }
646
647    /// Test greater or equal (>=) comparison between large positive and negative [`Q`]
648    /// (FLINT uses pointers)
649    #[test]
650    fn greater_equal_large() {
651        let max_1 = Q::from(u64::MAX);
652        let max_2 = Q::from(u64::MAX);
653        let max_negative = Q::from(i64::MIN);
654
655        assert!(max_1 >= max_2);
656        assert!(max_2 >= max_1);
657        assert!(max_1 >= max_1);
658
659        assert!(max_1 >= max_negative);
660        assert!(max_negative >= max_negative);
661    }
662
663    /// Compare a number close to `0` with `0`
664    #[test]
665    fn close_to_zero() {
666        let small = Q::from((1, u64::MAX));
667        let zero = Q::ZERO;
668
669        assert!(small > zero);
670        assert!(small >= zero);
671    }
672}
673
674/// Test that the [`PartialOrd`] trait is correctly implemented.
675#[cfg(test)]
676mod test_partial_ord_q_other {
677    use super::Q;
678    use crate::{integer::Z, integer_mod_q::Modulus};
679
680    /// Ensure that the function can be called with several types
681    #[test]
682    #[allow(clippy::op_ref)]
683    fn availability() {
684        let q = Q::from((2, 1));
685        let z = Z::from(2);
686        let modulus = Modulus::from(2);
687
688        assert!(q <= z);
689        assert!(q <= modulus);
690        assert!(q <= z.value);
691        assert!(q <= 2i8);
692        assert!(q <= 2u8);
693        assert!(q <= 2i16);
694        assert!(q <= 2u16);
695        assert!(q <= 2i32);
696        assert!(q <= 2u32);
697        assert!(q <= 2i64);
698        assert!(q <= 2u64);
699
700        assert!(z >= q);
701        assert!(modulus >= q);
702        assert!(z.value >= q);
703        assert!(2i8 >= q);
704        assert!(2u8 >= q);
705        assert!(2i16 >= q);
706        assert!(2u16 >= q);
707        assert!(2i32 >= q);
708        assert!(2u32 >= q);
709        assert!(2i64 >= q);
710        assert!(2u64 >= q);
711
712        assert!(&q <= &z);
713        assert!(&z >= &q);
714        assert!(&q <= &modulus);
715        assert!(&modulus >= &q);
716        assert!(&q <= &2i8);
717        assert!(&2i8 >= &q);
718    }
719}
720
721#[cfg(test)]
722mod test_ord {
723    use super::Q;
724    use std::cmp::{max, min};
725
726    // `cmp` is extensively tested in module `test_partial_eq`, hence omitted here
727
728    /// Check whether default implementations `max`, `min`, `clamp`
729    /// work properly for small numbers
730    #[test]
731    fn default_implementations_small() {
732        let a: Q = Q::from((10, 3));
733        let b: Q = Q::from((42, 4));
734
735        assert_eq!(b, max(a.clone(), b.clone()));
736        assert_eq!(a, min(a.clone(), b.clone()));
737
738        assert_eq!(a, Q::ZERO.clamp(a.clone(), b.clone()));
739        assert_eq!(a, a.clone().clamp(Q::ZERO, b.clone()));
740        assert_eq!(a, b.clamp(Q::ZERO, a.clone()));
741    }
742
743    /// Check whether default implementations `max`, `min`, `clamp`
744    /// work properly for large numbers
745    #[test]
746    fn default_implementations_large() {
747        let a: Q = Q::from(i64::MAX);
748        let b: Q = Q::from(u64::MAX);
749
750        assert_eq!(b, max(a.clone(), b.clone()));
751        assert_eq!(a, min(a.clone(), b.clone()));
752
753        assert_eq!(a, Q::ZERO.clamp(a.clone(), b.clone()));
754        assert_eq!(a, a.clone().clamp(Q::ZERO, b.clone()));
755        assert_eq!(a, b.clamp(Q::ZERO, a.clone()));
756    }
757}