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