Skip to main content

malachite_nz/gaussian_integer/comparison/
cmp_abs_primitive_float.rs

1// Copyright © 2026 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::gaussian_integer::GaussianInteger;
10use crate::natural::Natural;
11use core::cmp::Ordering::{self, Greater, Less};
12use malachite_base::num::arithmetic::traits::{AbsSquared, UnsignedAbs};
13use malachite_base::num::comparison::traits::PartialOrdAbs;
14use malachite_base::num::conversion::traits::IntegerMantissaAndExponent;
15
16macro_rules! impl_float {
17    ($t: ident) => {
18        impl PartialOrdAbs<$t> for GaussianInteger {
19            /// Compares the absolute values of a [`GaussianInteger`] and a primitive float.
20            ///
21            /// NaN is not comparable to any [`GaussianInteger`]. $\infty$ and $-\infty$ are greater
22            /// in absolute value than any [`GaussianInteger`]. When the squared absolute values
23            /// must be compared, the float's square is represented exactly as an odd square times a
24            /// power of two, so the comparison is exact.
25            ///
26            /// # Worst-case complexity
27            /// $T(n) = O(n \log n \log\log n)$
28            ///
29            /// $M(n) = O(n \log n)$
30            ///
31            /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of
32            /// significant bits of the real and imaginary parts of `self` and
33            /// `other.sci_exponent().abs()`.
34            ///
35            /// # Examples
36            /// See [here](super::cmp_abs_primitive_float#partial_cmp_abs).
37            fn partial_cmp_abs(&self, other: &$t) -> Option<Ordering> {
38                if other.is_nan() {
39                    None
40                } else if !other.is_finite() {
41                    Some(Less)
42                } else if self.imaginary == 0u32 {
43                    self.real.partial_cmp_abs(other)
44                } else if self.real == 0u32 {
45                    self.imaginary.partial_cmp_abs(other)
46                } else if !self.real.lt_abs(other) || !self.imaginary.lt_abs(other) {
47                    // This also covers a zero float, whose absolute value cannot exceed either
48                    // nonzero component.
49                    Some(Greater)
50                } else {
51                    // |other| = m * 2^e with m odd, so |other|^2 = m^2 * 2^(2e), compared exactly
52                    // against |self|^2 by shifting whichever side has the nonnegative exponent.
53                    let (m, e) = other.abs().integer_mantissa_and_exponent();
54                    let m_squared = Natural::from(u128::from(m) * u128::from(m));
55                    let abs_squared = self.abs_squared().unsigned_abs();
56                    let shift = e.unsigned_abs() << 1;
57                    Some(if e >= 0 {
58                        abs_squared.cmp(&(m_squared << shift))
59                    } else {
60                        (abs_squared << shift).cmp(&m_squared)
61                    })
62                }
63            }
64        }
65
66        impl PartialOrdAbs<GaussianInteger> for $t {
67            /// Compares the absolute values of a primitive float and a [`GaussianInteger`].
68            ///
69            /// NaN is not comparable to any [`GaussianInteger`]. $\infty$ and $-\infty$ are greater
70            /// in absolute value than any [`GaussianInteger`].
71            ///
72            /// # Worst-case complexity
73            /// $T(n) = O(n \log n \log\log n)$
74            ///
75            /// $M(n) = O(n \log n)$
76            ///
77            /// where $T$ is time, $M$ is additional memory, and $n$ is the maximum number of
78            /// significant bits of the real and imaginary parts of `other` and
79            /// `self.sci_exponent().abs()`.
80            ///
81            /// # Examples
82            /// See [here](super::cmp_abs_primitive_float#partial_cmp_abs).
83            #[inline]
84            fn partial_cmp_abs(&self, other: &GaussianInteger) -> Option<Ordering> {
85                other.partial_cmp_abs(self).map(Ordering::reverse)
86            }
87        }
88    };
89}
90apply_to_primitive_floats!(impl_float);