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