malachite_float/comparison/
cmp_abs.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::InnerFloat::{Finite, Infinity, NaN, Zero};
10use crate::{ComparableFloat, ComparableFloatRef, Float};
11use core::cmp::Ordering::{self, *};
12use malachite_base::num::comparison::traits::{OrdAbs, PartialOrdAbs};
13
14impl PartialOrdAbs for Float {
15    /// Compares the absolute values of two [`Float`]s.
16    ///
17    /// This implementation follows the IEEE 754 standard. `NaN` is not comparable to anything, not
18    /// even itself. [`Float`]s with different precisions are equal if they represent the same
19    /// numeric value.
20    ///
21    /// For different comparison behavior that provides a total order, consider using
22    /// [`ComparableFloat`] or [`ComparableFloatRef`].
23    ///
24    /// # Worst-case complexity
25    /// $T(n) = O(n)$
26    ///
27    /// $M(n) = O(1)$
28    ///
29    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
30    /// other.significant_bits())`.
31    ///
32    /// # Examples
33    /// ```
34    /// use malachite_base::num::basic::traits::{
35    ///     Infinity, NaN, NegativeInfinity, NegativeOne, NegativeZero, One, OneHalf, Zero,
36    /// };
37    /// use malachite_base::num::comparison::traits::PartialOrdAbs;
38    /// use malachite_float::Float;
39    /// use std::cmp::Ordering::*;
40    ///
41    /// assert_eq!(Float::NAN.partial_cmp_abs(&Float::NAN), None);
42    /// assert_eq!(
43    ///     Float::ZERO.partial_cmp_abs(&Float::NEGATIVE_ZERO),
44    ///     Some(Equal)
45    /// );
46    /// assert_eq!(
47    ///     Float::ONE.partial_cmp_abs(&Float::one_prec(100)),
48    ///     Some(Equal)
49    /// );
50    /// assert!(Float::INFINITY.gt_abs(&Float::ONE));
51    /// assert!(Float::NEGATIVE_INFINITY.gt_abs(&Float::ONE));
52    /// assert!(Float::ONE_HALF.lt_abs(&Float::ONE));
53    /// assert!(Float::ONE_HALF.lt_abs(&Float::NEGATIVE_ONE));
54    /// ```
55    fn partial_cmp_abs(&self, other: &Float) -> Option<Ordering> {
56        match (self, other) {
57            (float_nan!(), _) | (_, float_nan!()) => None,
58            (float_either_infinity!(), float_either_infinity!())
59            | (float_either_zero!(), float_either_zero!()) => Some(Equal),
60            (float_either_infinity!(), _) | (_, float_either_zero!()) => Some(Greater),
61            (_, float_either_infinity!()) | (float_either_zero!(), _) => Some(Less),
62            (
63                Float(Finite {
64                    exponent: e_x,
65                    significand: x,
66                    ..
67                }),
68                Float(Finite {
69                    exponent: e_y,
70                    significand: y,
71                    ..
72                }),
73            ) => Some(e_x.cmp(e_y).then_with(|| x.cmp_normalized_no_shift(y))),
74        }
75    }
76}
77
78impl<'a> OrdAbs for ComparableFloatRef<'a> {
79    /// Compares the absolute values of two [`ComparableFloatRef`]s.
80    ///
81    /// This implementation does not follow the IEEE 754 standard. This is how
82    /// [`ComparableFloatRef`]s are ordered by absolute value, from least to greatest:
83    ///   - NaN
84    ///   - Positive and negative zero
85    ///   - Nonzero finite floats
86    ///   - $\infty$ and $-\infty$
87    ///
88    /// For different comparison behavior that follows the IEEE 754 standard, consider just using
89    /// [`Float`].
90    ///
91    /// # Worst-case complexity
92    /// $T(n) = O(n)$
93    ///
94    /// $M(n) = O(1)$
95    ///
96    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
97    /// other.significant_bits())`.
98    ///
99    /// # Examples
100    /// ```
101    /// use malachite_base::num::basic::traits::{
102    ///     Infinity, NaN, NegativeInfinity, NegativeOne, NegativeZero, One, OneHalf, Zero,
103    /// };
104    /// use malachite_base::num::comparison::traits::PartialOrdAbs;
105    /// use malachite_float::{ComparableFloatRef, Float};
106    /// use std::cmp::Ordering::*;
107    ///
108    /// assert_eq!(
109    ///     ComparableFloatRef(&Float::NAN).partial_cmp_abs(&ComparableFloatRef(&Float::NAN)),
110    ///     Some(Equal)
111    /// );
112    /// assert_eq!(
113    ///     ComparableFloatRef(&Float::ZERO)
114    ///         .partial_cmp_abs(&ComparableFloatRef(&Float::NEGATIVE_ZERO)),
115    ///     Some(Equal)
116    /// );
117    /// assert!(ComparableFloatRef(&Float::ONE).lt_abs(&ComparableFloatRef(&Float::one_prec(100))));
118    /// assert!(ComparableFloatRef(&Float::INFINITY).gt_abs(&ComparableFloatRef(&Float::ONE)));
119    /// assert!(
120    ///     ComparableFloatRef(&Float::NEGATIVE_INFINITY).gt_abs(&ComparableFloatRef(&Float::ONE))
121    /// );
122    /// assert!(ComparableFloatRef(&Float::ONE_HALF).lt_abs(&ComparableFloatRef(&Float::ONE)));
123    /// assert!(
124    ///     ComparableFloatRef(&Float::ONE_HALF).lt_abs(&ComparableFloatRef(&Float::NEGATIVE_ONE))
125    /// );
126    /// ```
127    #[allow(clippy::match_same_arms)]
128    fn cmp_abs(&self, other: &ComparableFloatRef<'a>) -> Ordering {
129        match (&self.0, &other.0) {
130            (float_nan!(), float_nan!())
131            | (float_either_infinity!(), float_either_infinity!())
132            | (float_either_zero!(), float_either_zero!()) => Equal,
133            (float_either_infinity!(), _) | (_, float_nan!()) => Greater,
134            (_, float_either_infinity!()) | (float_nan!(), _) => Less,
135            (float_either_zero!(), _) => Less,
136            (_, float_either_zero!()) => Greater,
137            (
138                Float(Finite {
139                    exponent: e_x,
140                    precision: p_x,
141                    significand: x,
142                    ..
143                }),
144                Float(Finite {
145                    exponent: e_y,
146                    precision: p_y,
147                    significand: y,
148                    ..
149                }),
150            ) => e_x
151                .cmp(e_y)
152                .then_with(|| x.cmp_normalized_no_shift(y))
153                .then_with(|| p_x.cmp(p_y)),
154        }
155    }
156}
157
158impl PartialOrdAbs for ComparableFloatRef<'_> {
159    /// Compares the absolute values of two [`ComparableFloatRef`]s.
160    ///
161    /// See the documentation for the [`Ord`] implementation.
162    #[inline]
163    fn partial_cmp_abs(&self, other: &ComparableFloatRef) -> Option<Ordering> {
164        Some(self.cmp_abs(other))
165    }
166}
167
168impl OrdAbs for ComparableFloat {
169    /// Compares the absolute values of two [`ComparableFloat`]s.
170    ///
171    /// This implementation does not follow the IEEE 754 standard. This is how [`ComparableFloat`]s
172    /// are ordered by absolute value, from least to greatest:
173    ///   - NaN
174    ///   - Positive and negative zero
175    ///   - Nonzero finite floats
176    ///   - $\infty$ and $-\infty$
177    ///
178    /// For different comparison behavior that follows the IEEE 754 standard, consider just using
179    /// [`Float`].
180    ///
181    /// # Worst-case complexity
182    /// $T(n) = O(n)$
183    ///
184    /// $M(n) = O(1)$
185    ///
186    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
187    /// other.significant_bits())`.
188    ///
189    /// # Examples
190    /// ```
191    /// use malachite_base::num::basic::traits::{
192    ///     Infinity, NaN, NegativeInfinity, NegativeOne, NegativeZero, One, OneHalf, Zero,
193    /// };
194    /// use malachite_base::num::comparison::traits::PartialOrdAbs;
195    /// use malachite_float::{ComparableFloat, Float};
196    /// use std::cmp::Ordering::*;
197    ///
198    /// assert_eq!(
199    ///     ComparableFloat(Float::NAN).partial_cmp_abs(&ComparableFloat(Float::NAN)),
200    ///     Some(Equal)
201    /// );
202    /// assert_eq!(
203    ///     ComparableFloat(Float::ZERO).partial_cmp_abs(&ComparableFloat(Float::NEGATIVE_ZERO)),
204    ///     Some(Equal)
205    /// );
206    /// assert!(ComparableFloat(Float::ONE).lt_abs(&ComparableFloat(Float::one_prec(100))));
207    /// assert!(ComparableFloat(Float::INFINITY).gt_abs(&ComparableFloat(Float::ONE)));
208    /// assert!(ComparableFloat(Float::NEGATIVE_INFINITY).gt_abs(&ComparableFloat(Float::ONE)));
209    /// assert!(ComparableFloat(Float::ONE_HALF).lt_abs(&ComparableFloat(Float::ONE)));
210    /// assert!(ComparableFloat(Float::ONE_HALF).lt_abs(&ComparableFloat(Float::NEGATIVE_ONE)));
211    /// ```
212    #[inline]
213    fn cmp_abs(&self, other: &ComparableFloat) -> Ordering {
214        self.as_ref().cmp_abs(&other.as_ref())
215    }
216}
217
218impl PartialOrdAbs for ComparableFloat {
219    /// Compares the absolute values of two [`ComparableFloatRef`]s.
220    ///
221    /// See the documentation for the [`Ord`] implementation.
222    #[inline]
223    fn partial_cmp_abs(&self, other: &ComparableFloat) -> Option<Ordering> {
224        Some(self.as_ref().cmp_abs(&other.as_ref()))
225    }
226}