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}