malachite_float/comparison/partial_cmp_primitive_int.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::Float;
10use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
11use core::cmp::Ordering::{self, *};
12use malachite_base::num::arithmetic::traits::UnsignedAbs;
13use malachite_base::num::basic::signeds::PrimitiveSigned;
14use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
15use malachite_nz::natural::Natural;
16
17fn float_partial_cmp_unsigned<T: PrimitiveUnsigned>(x: &Float, y: &T) -> Option<Ordering>
18where
19 Natural: From<T>,
20{
21 match (x, y) {
22 (float_nan!(), _) => None,
23 (float_infinity!(), _) => Some(Greater),
24 (float_negative_infinity!(), _) => Some(Less),
25 (float_either_zero!(), _) => Some(if *y == T::ZERO { Equal } else { Less }),
26 (
27 Float(Finite {
28 sign: s_x,
29 exponent: e_x,
30 significand: sig_x,
31 ..
32 }),
33 y,
34 ) => Some(if !s_x {
35 Less
36 } else if *y == T::ZERO {
37 Greater
38 } else if *e_x <= 0 {
39 Less
40 } else {
41 u64::from(e_x.unsigned_abs())
42 .cmp(&y.significant_bits())
43 .then_with(|| sig_x.cmp_normalized(&Natural::from(*y)))
44 }),
45 }
46}
47
48macro_rules! impl_from_unsigned {
49 ($t: ident) => {
50 impl PartialOrd<$t> for Float {
51 /// Compares a [`Float`] to an unsigned primitive integer.
52 ///
53 /// NaN is not comparable to any primitive integer. $\infty$ is greater than any
54 /// primitive integer, and $-\infty$ is less. Both the [`Float`] zero and the [`Float`]
55 /// negative zero are equal to the integer zero.
56 ///
57 /// # Worst-case complexity
58 /// $T(n) = O(n)$
59 ///
60 /// $M(n) = O(1)$
61 ///
62 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
63 ///
64 /// # Examples
65 /// See [here](super::partial_cmp_primitive_int#partial_cmp).
66 #[inline]
67 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
68 float_partial_cmp_unsigned(self, other)
69 }
70 }
71
72 impl PartialOrd<Float> for $t {
73 /// Compares an unsigned primitive integer to a [`Float`].
74 ///
75 /// No integer is comparable to NaN. Every integer is smaller than $\infty$ and greater
76 /// than $-\infty$. The integer zero is equal to both the [`Float`] zero and the
77 /// [`Float`] negative zero.
78 ///
79 /// # Worst-case complexity
80 /// $T(n) = O(n)$
81 ///
82 /// $M(n) = O(1)$
83 ///
84 /// where $T$ is time, $M$ is additional memory, and $n$ is `other.significant_bits()`.
85 ///
86 /// # Examples
87 /// See [here](super::partial_cmp_primitive_int#partial_cmp).
88 #[inline]
89 fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
90 other.partial_cmp(self).map(Ordering::reverse)
91 }
92 }
93 };
94}
95apply_to_unsigneds!(impl_from_unsigned);
96
97fn float_partial_cmp_signed<T: PrimitiveSigned>(x: &Float, y: &T) -> Option<Ordering>
98where
99 Natural: From<<T as UnsignedAbs>::Output>,
100{
101 match (x, y) {
102 (float_nan!(), _) => None,
103 (float_infinity!(), _) => Some(Greater),
104 (float_negative_infinity!(), _) => Some(Less),
105 (float_either_zero!(), _) => Some(T::ZERO.cmp(y)),
106 (
107 Float(Finite {
108 sign: s_x,
109 exponent: e_x,
110 significand: sig_x,
111 ..
112 }),
113 y,
114 ) => {
115 let s_y = *y > T::ZERO;
116 let s_cmp = s_x.cmp(&s_y);
117 if s_cmp != Equal {
118 return Some(s_cmp);
119 }
120 let abs_cmp = if *y == T::ZERO {
121 Greater
122 } else if *e_x <= 0 {
123 Less
124 } else {
125 u64::from(e_x.unsigned_abs())
126 .cmp(&y.significant_bits())
127 .then_with(|| sig_x.cmp_normalized(&Natural::from(y.unsigned_abs())))
128 };
129 Some(if s_y { abs_cmp } else { abs_cmp.reverse() })
130 }
131 }
132}
133
134macro_rules! impl_from_signed {
135 ($t: ident) => {
136 impl PartialOrd<$t> for Float {
137 /// Compares a [`Float`] to a signed primitive integer.
138 ///
139 /// NaN is not comparable to any primitive integer. $\infty$ is greater than any
140 /// primitive integer, and $-\infty$ is less. Both the [`Float`] zero and the [`Float`]
141 /// negative zero are equal to the integer zero.
142 ///
143 /// # Worst-case complexity
144 /// $T(n) = O(n)$
145 ///
146 /// $M(n) = O(1)$
147 ///
148 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
149 ///
150 /// # Examples
151 /// See [here](super::partial_cmp_primitive_int#partial_cmp).
152 #[inline]
153 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
154 float_partial_cmp_signed(self, other)
155 }
156 }
157
158 impl PartialOrd<Float> for $t {
159 /// Compares a signed primitive integer to a [`Float`].
160 ///
161 /// No integer is comparable to NaN. Every integer is smaller than $\infty$ and greater
162 /// than $-\infty$. The integer zero is equal to both the [`Float`] zero and the
163 /// [`Float`] negative zero.
164 ///
165 /// # Worst-case complexity
166 /// $T(n) = O(n)$
167 ///
168 /// $M(n) = O(1)$
169 ///
170 /// where $T$ is time, $M$ is additional memory, and $n$ is `other.significant_bits()`.
171 ///
172 /// # Examples
173 /// See [here](super::partial_cmp_primitive_int#partial_cmp).
174 #[inline]
175 fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
176 other.partial_cmp(self).map(Ordering::reverse)
177 }
178 }
179 };
180}
181apply_to_signeds!(impl_from_signed);