Skip to main content

qfall_math/rational/q/
cmp.rs

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