malachite_float/float/basic/classification.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::InnerFloat::{Finite, Infinity, NaN, Zero};
10use crate::{
11 Float, float_either_infinity, float_either_zero, float_finite, float_nan, float_negative_zero,
12 float_zero,
13};
14use core::num::FpCategory;
15
16impl Float {
17 /// Determines whether a [`Float`] is NaN.
18 ///
19 /// # Worst-case complexity
20 /// Constant time and additional memory.
21 ///
22 /// # Examples
23 /// ```
24 /// use malachite_base::num::basic::traits::{NaN, One};
25 /// use malachite_float::Float;
26 ///
27 /// assert_eq!(Float::NAN.is_nan(), true);
28 /// assert_eq!(Float::ONE.is_nan(), false);
29 /// ```
30 #[inline]
31 pub const fn is_nan(&self) -> bool {
32 matches!(self, float_nan!())
33 }
34
35 /// Determines whether a [`Float`] is finite.
36 ///
37 /// NaN is not finite.
38 ///
39 /// # Worst-case complexity
40 /// Constant time and additional memory.
41 ///
42 /// # Examples
43 /// ```
44 /// use malachite_base::num::basic::traits::{Infinity, NaN, One};
45 /// use malachite_float::Float;
46 ///
47 /// assert_eq!(Float::NAN.is_finite(), false);
48 /// assert_eq!(Float::INFINITY.is_finite(), false);
49 /// assert_eq!(Float::ONE.is_finite(), true);
50 /// ```
51 #[inline]
52 pub const fn is_finite(&self) -> bool {
53 matches!(self, Self(Zero { .. } | Finite { .. }))
54 }
55
56 /// Determines whether a [`Float`] is infinite.
57 ///
58 /// NaN is not infinite.
59 ///
60 /// # Worst-case complexity
61 /// Constant time and additional memory.
62 ///
63 /// # Examples
64 /// ```
65 /// use malachite_base::num::basic::traits::{Infinity, NaN, One};
66 /// use malachite_float::Float;
67 ///
68 /// assert_eq!(Float::NAN.is_infinite(), false);
69 /// assert_eq!(Float::INFINITY.is_infinite(), true);
70 /// assert_eq!(Float::ONE.is_infinite(), false);
71 /// ```
72 #[inline]
73 pub const fn is_infinite(&self) -> bool {
74 matches!(self, float_either_infinity!())
75 }
76
77 /// Determines whether a [`Float`] is positive zero.
78 ///
79 /// # Worst-case complexity
80 /// Constant time and additional memory.
81 ///
82 /// # Examples
83 /// ```
84 /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeZero, One, Zero};
85 /// use malachite_float::Float;
86 ///
87 /// assert_eq!(Float::NAN.is_positive_zero(), false);
88 /// assert_eq!(Float::INFINITY.is_positive_zero(), false);
89 /// assert_eq!(Float::ONE.is_positive_zero(), false);
90 /// assert_eq!(Float::ZERO.is_positive_zero(), true);
91 /// assert_eq!(Float::NEGATIVE_ZERO.is_positive_zero(), false);
92 /// ```
93 #[inline]
94 pub const fn is_positive_zero(&self) -> bool {
95 matches!(self, float_zero!())
96 }
97
98 /// Determines whether a [`Float`] is negative zero.
99 ///
100 /// # Worst-case complexity
101 /// Constant time and additional memory.
102 ///
103 /// # Examples
104 /// ```
105 /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeZero, One, Zero};
106 /// use malachite_float::Float;
107 ///
108 /// assert_eq!(Float::NAN.is_negative_zero(), false);
109 /// assert_eq!(Float::INFINITY.is_negative_zero(), false);
110 /// assert_eq!(Float::ONE.is_negative_zero(), false);
111 /// assert_eq!(Float::ZERO.is_negative_zero(), false);
112 /// assert_eq!(Float::NEGATIVE_ZERO.is_negative_zero(), true);
113 /// ```
114 #[inline]
115 pub const fn is_negative_zero(&self) -> bool {
116 matches!(self, float_negative_zero!())
117 }
118
119 /// Determines whether a [`Float`] is zero (positive or negative).
120 ///
121 /// # Worst-case complexity
122 /// Constant time and additional memory.
123 ///
124 /// # Examples
125 /// ```
126 /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeZero, One, Zero};
127 /// use malachite_float::Float;
128 ///
129 /// assert_eq!(Float::NAN.is_zero(), false);
130 /// assert_eq!(Float::INFINITY.is_zero(), false);
131 /// assert_eq!(Float::ONE.is_zero(), false);
132 /// assert_eq!(Float::ZERO.is_zero(), true);
133 /// assert_eq!(Float::NEGATIVE_ZERO.is_zero(), true);
134 /// ```
135 #[inline]
136 pub const fn is_zero(&self) -> bool {
137 matches!(self, float_either_zero!())
138 }
139
140 /// Determines whether a [`Float`] is normal, that is, finite and nonzero.
141 ///
142 /// There is no notion of subnormal [`Float`]s.
143 ///
144 /// # Worst-case complexity
145 /// Constant time and additional memory.
146 ///
147 /// # Examples
148 /// ```
149 /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeZero, One, Zero};
150 /// use malachite_float::Float;
151 ///
152 /// assert_eq!(Float::NAN.is_normal(), false);
153 /// assert_eq!(Float::INFINITY.is_normal(), false);
154 /// assert_eq!(Float::ZERO.is_normal(), false);
155 /// assert_eq!(Float::NEGATIVE_ZERO.is_normal(), false);
156 /// assert_eq!(Float::ONE.is_normal(), true);
157 /// ```
158 pub const fn is_normal(&self) -> bool {
159 matches!(self, float_finite!())
160 }
161
162 /// Determines whether a [`Float`]'s sign is positive.
163 ///
164 /// A NaN has no sign, so this function returns false when given a NaN.
165 ///
166 /// # Worst-case complexity
167 /// Constant time and additional memory.
168 ///
169 /// # Examples
170 /// ```
171 /// use malachite_base::num::basic::traits::{
172 /// Infinity, NaN, NegativeInfinity, NegativeOne, NegativeZero, One, Zero,
173 /// };
174 /// use malachite_float::Float;
175 ///
176 /// assert_eq!(Float::NAN.is_sign_positive(), false);
177 /// assert_eq!(Float::INFINITY.is_sign_positive(), true);
178 /// assert_eq!(Float::NEGATIVE_INFINITY.is_sign_positive(), false);
179 /// assert_eq!(Float::ZERO.is_sign_positive(), true);
180 /// assert_eq!(Float::NEGATIVE_ZERO.is_sign_positive(), false);
181 /// assert_eq!(Float::ONE.is_sign_positive(), true);
182 /// assert_eq!(Float::NEGATIVE_ONE.is_sign_positive(), false);
183 /// ```
184 pub const fn is_sign_positive(&self) -> bool {
185 match self {
186 float_nan!() => false,
187 Self(Infinity { sign } | Finite { sign, .. } | Zero { sign, .. }) => *sign,
188 }
189 }
190
191 /// Determines whether a [`Float`]'s sign is negative.
192 ///
193 /// A NaN has no sign, so this function returns false when given a NaN.
194 ///
195 /// # Worst-case complexity
196 /// Constant time and additional memory.
197 ///
198 /// # Examples
199 /// ```
200 /// use malachite_base::num::basic::traits::{
201 /// Infinity, NaN, NegativeInfinity, NegativeOne, NegativeZero, One, Zero,
202 /// };
203 /// use malachite_float::Float;
204 ///
205 /// assert_eq!(Float::NAN.is_sign_negative(), false);
206 /// assert_eq!(Float::INFINITY.is_sign_negative(), false);
207 /// assert_eq!(Float::NEGATIVE_INFINITY.is_sign_negative(), true);
208 /// assert_eq!(Float::ZERO.is_sign_negative(), false);
209 /// assert_eq!(Float::NEGATIVE_ZERO.is_sign_negative(), true);
210 /// assert_eq!(Float::ONE.is_sign_negative(), false);
211 /// assert_eq!(Float::NEGATIVE_ONE.is_sign_negative(), true);
212 /// ```
213 pub const fn is_sign_negative(&self) -> bool {
214 match self {
215 float_nan!() => false,
216 Self(Infinity { sign } | Finite { sign, .. } | Zero { sign, .. }) => !*sign,
217 }
218 }
219
220 /// Classifies a [`Float`] into one of several categories.
221 ///
222 /// # Worst-case complexity
223 /// Constant time and additional memory.
224 ///
225 /// # Examples
226 /// ```
227 /// use malachite_base::num::basic::traits::{
228 /// Infinity, NaN, NegativeInfinity, NegativeOne, NegativeZero, One, Zero,
229 /// };
230 /// use malachite_float::Float;
231 /// use std::num::FpCategory;
232 ///
233 /// assert_eq!(Float::NAN.classify(), FpCategory::Nan);
234 /// assert_eq!(Float::INFINITY.classify(), FpCategory::Infinite);
235 /// assert_eq!(Float::NEGATIVE_INFINITY.classify(), FpCategory::Infinite);
236 /// assert_eq!(Float::ZERO.classify(), FpCategory::Zero);
237 /// assert_eq!(Float::NEGATIVE_ZERO.classify(), FpCategory::Zero);
238 /// assert_eq!(Float::ONE.classify(), FpCategory::Normal);
239 /// assert_eq!(Float::NEGATIVE_ONE.classify(), FpCategory::Normal);
240 /// ```
241 pub const fn classify(&self) -> FpCategory {
242 match self {
243 float_nan!() => FpCategory::Nan,
244 float_either_infinity!() => FpCategory::Infinite,
245 Self(Zero { .. }) => FpCategory::Zero,
246 _ => FpCategory::Normal,
247 }
248 }
249
250 /// Turns a NaN into a `None` and wraps any non-NaN [`Float`] with a `Some`. The [`Float`] is
251 /// taken by value.
252 ///
253 /// # Worst-case complexity
254 /// Constant time and additional memory.
255 ///
256 /// # Examples
257 /// ```
258 /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeZero, One, Zero};
259 /// use malachite_float::Float;
260 ///
261 /// assert_eq!(Float::NAN.into_non_nan(), None);
262 /// assert_eq!(Float::INFINITY.into_non_nan(), Some(Float::INFINITY));
263 /// assert_eq!(Float::ZERO.into_non_nan(), Some(Float::ZERO));
264 /// assert_eq!(
265 /// Float::NEGATIVE_ZERO.into_non_nan(),
266 /// Some(Float::NEGATIVE_ZERO)
267 /// );
268 /// assert_eq!(Float::ONE.into_non_nan(), Some(Float::ONE));
269 /// ```
270 #[allow(clippy::missing_const_for_fn)] // destructor doesn't work with const
271 pub fn into_non_nan(self) -> Option<Self> {
272 match self {
273 float_nan!() => None,
274 x => Some(x),
275 }
276 }
277
278 /// Turns a NaN into a `None` and wraps any non-NaN [`Float`] with a `Some`. The [`Float`] is
279 /// taken by reference.
280 ///
281 /// # Worst-case complexity
282 /// $T(n) = O(n)$
283 ///
284 /// $M(n) = O(n)$
285 ///
286 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
287 ///
288 /// # Examples
289 /// ```
290 /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeZero, One, Zero};
291 /// use malachite_float::Float;
292 ///
293 /// assert_eq!(Float::NAN.to_non_nan(), None);
294 /// assert_eq!(Float::INFINITY.to_non_nan(), Some(Float::INFINITY));
295 /// assert_eq!(Float::ZERO.to_non_nan(), Some(Float::ZERO));
296 /// assert_eq!(
297 /// Float::NEGATIVE_ZERO.to_non_nan(),
298 /// Some(Float::NEGATIVE_ZERO)
299 /// );
300 /// assert_eq!(Float::ONE.to_non_nan(), Some(Float::ONE));
301 /// ```
302 #[allow(clippy::missing_const_for_fn)] // destructor doesn't work with const
303 pub fn to_non_nan(&self) -> Option<Self> {
304 match self {
305 float_nan!() => None,
306 x => Some(x.clone()),
307 }
308 }
309
310 /// Turns any [`Float`] that's NaN or infinite into a `None` and wraps any finite [`Float`] with
311 /// a `Some`. The [`Float`] is taken by value.
312 ///
313 /// # Worst-case complexity
314 /// Constant time and additional memory.
315 ///
316 /// # Examples
317 /// ```
318 /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeZero, One, Zero};
319 /// use malachite_float::Float;
320 ///
321 /// assert_eq!(Float::NAN.into_finite(), None);
322 /// assert_eq!(Float::INFINITY.into_finite(), None);
323 /// assert_eq!(Float::ZERO.into_finite(), Some(Float::ZERO));
324 /// assert_eq!(
325 /// Float::NEGATIVE_ZERO.into_finite(),
326 /// Some(Float::NEGATIVE_ZERO)
327 /// );
328 /// assert_eq!(Float::ONE.into_finite(), Some(Float::ONE));
329 /// ```
330 #[allow(clippy::missing_const_for_fn)] // destructor doesn't work with const
331 pub fn into_finite(self) -> Option<Self> {
332 match self {
333 Self(NaN | Infinity { .. }) => None,
334 x => Some(x),
335 }
336 }
337
338 /// Turns any [`Float`] that's NaN or infinite into a `None` and wraps any finite [`Float`] with
339 /// a `Some`. The [`Float`] is taken by reference.
340 ///
341 /// # Worst-case complexity
342 /// $T(n) = O(n)$
343 ///
344 /// $M(n) = O(n)$
345 ///
346 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
347 ///
348 /// # Examples
349 /// ```
350 /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeZero, One, Zero};
351 /// use malachite_float::Float;
352 ///
353 /// assert_eq!(Float::NAN.to_finite(), None);
354 /// assert_eq!(Float::INFINITY.to_finite(), None);
355 /// assert_eq!(Float::ZERO.to_finite(), Some(Float::ZERO));
356 /// assert_eq!(Float::NEGATIVE_ZERO.to_finite(), Some(Float::NEGATIVE_ZERO));
357 /// assert_eq!(Float::ONE.to_finite(), Some(Float::ONE));
358 /// ```
359 pub fn to_finite(&self) -> Option<Self> {
360 match self {
361 Self(NaN | Infinity { .. }) => None,
362 x => Some(x.clone()),
363 }
364 }
365}