malachite_q/comparison/
partial_cmp_abs_integer.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::Rational;
10use core::cmp::Ordering::{self, *};
11use malachite_base::num::arithmetic::traits::Sign;
12use malachite_base::num::basic::traits::One;
13use malachite_base::num::comparison::traits::PartialOrdAbs;
14use malachite_base::num::conversion::traits::ExactFrom;
15use malachite_base::num::logic::traits::SignificantBits;
16use malachite_nz::integer::Integer;
17use malachite_nz::natural::Natural;
18
19impl PartialOrdAbs<Integer> for Rational {
20    /// Compares the absolute values of a [`Rational`] and an [`Integer`].
21    ///
22    /// # Worst-case complexity
23    /// $T(n) = O(n \log n \log\log n)$
24    ///
25    /// $M(n) = O(n \log n)$
26    ///
27    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
28    /// other.significant_bits())`.
29    ///
30    /// # Examples
31    /// ```
32    /// use malachite_base::num::comparison::traits::PartialOrdAbs;
33    /// use malachite_nz::integer::Integer;
34    /// use malachite_q::Rational;
35    /// use std::cmp::Ordering::*;
36    ///
37    /// assert_eq!(
38    ///     Rational::from_signeds(22, 7).partial_cmp_abs(&Integer::from(3)),
39    ///     Some(Greater)
40    /// );
41    /// assert_eq!(
42    ///     Rational::from_signeds(-22, 7).partial_cmp_abs(&Integer::from(-3)),
43    ///     Some(Greater)
44    /// );
45    /// ```
46    fn partial_cmp_abs(&self, other: &Integer) -> Option<Ordering> {
47        // First check whether either value is zero
48        let self_sign = self.numerator_ref().sign();
49        let other_sign = other.unsigned_abs_ref().sign();
50        let sign_cmp = self_sign.cmp(&other_sign);
51        if sign_cmp != Equal || self_sign == Equal {
52            return Some(sign_cmp);
53        }
54        // Then check if one is < 1 and the other is > 1
55        let self_cmp_one = self.numerator.cmp(&self.denominator);
56        let other_cmp_one = other.unsigned_abs_ref().cmp(&Natural::ONE);
57        let one_cmp = self_cmp_one.cmp(&other_cmp_one);
58        if one_cmp != Equal {
59            return Some(one_cmp);
60        }
61        // Then compare numerators and denominators
62        let n_cmp = self.numerator.cmp(other.unsigned_abs_ref());
63        let d_cmp = self.denominator.cmp(&Natural::ONE);
64        if n_cmp == Equal && d_cmp == Equal {
65            return Some(Equal);
66        }
67        let nd_cmp = n_cmp.cmp(&d_cmp);
68        if nd_cmp != Equal {
69            return Some(nd_cmp);
70        }
71        // Then compare floor ∘ log_2 ∘ abs
72        let log_cmp = self
73            .floor_log_base_2_abs()
74            .cmp(&i64::exact_from(other.significant_bits() - 1));
75        if log_cmp != Equal {
76            return Some(log_cmp);
77        }
78        // Finally, cross-multiply.
79        Some(
80            self.numerator
81                .cmp(&(&self.denominator * other.unsigned_abs_ref())),
82        )
83    }
84}
85
86impl PartialOrdAbs<Rational> for Integer {
87    /// Compares the absolute values of an [`Integer`] and a [`Rational`].
88    ///
89    /// # Worst-case complexity
90    /// $T(n) = O(n \log n \log\log n)$
91    ///
92    /// $M(n) = O(n \log n)$
93    ///
94    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
95    /// other.significant_bits())`.
96    ///
97    /// # Examples
98    /// ```
99    /// use malachite_base::num::comparison::traits::PartialOrdAbs;
100    /// use malachite_nz::integer::Integer;
101    /// use malachite_q::Rational;
102    /// use std::cmp::Ordering::*;
103    ///
104    /// assert_eq!(
105    ///     Integer::from(3).partial_cmp_abs(&Rational::from_signeds(22, 7)),
106    ///     Some(Less)
107    /// );
108    /// assert_eq!(
109    ///     Integer::from(-3).partial_cmp_abs(&Rational::from_signeds(-22, 7)),
110    ///     Some(Less)
111    /// );
112    /// ```
113    #[inline]
114    fn partial_cmp_abs(&self, other: &Rational) -> Option<Ordering> {
115        other.partial_cmp_abs(self).map(Ordering::reverse)
116    }
117}