malachite_float/conversion/natural_from_float.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, Zero};
10use crate::{Float, significand_bits};
11use core::cmp::Ordering::{self, *};
12use malachite_base::num::arithmetic::traits::{DivisibleByPowerOf2, ShrRound};
13use malachite_base::num::basic::traits::{One, Zero as ZeroTrait};
14use malachite_base::num::conversion::from::UnsignedFromFloatError;
15use malachite_base::num::conversion::traits::{ConvertibleFrom, RoundingFrom};
16use malachite_base::rounding_modes::RoundingMode::{self, *};
17use malachite_nz::natural::Natural;
18
19impl RoundingFrom<Float> for Natural {
20 /// Converts a [`Float`] to a [`Natural`], using a specified [`RoundingMode`] and taking the
21 /// [`Float`] by value. An [`Ordering`] is also returned, indicating whether the returned value
22 /// is less than, equal to, or greater than the original value.
23 ///
24 /// If the [`Float`] is negative (including $-\infty$), then it will be rounded to zero when the
25 /// [`RoundingMode`] is `Ceiling`, `Down`, or `Nearest`. Otherwise, this function will panic.
26 ///
27 /// If the [`Float`] is NaN or $\infty$, the function will panic regardless of the rounding
28 /// mode.
29 ///
30 /// # Worst-case complexity
31 /// $T(n) = O(n)$
32 ///
33 /// $M(n) = O(n)$
34 ///
35 /// where $T$ is time, $M$ is additional memory, and $n$ is `f.complexity()`.
36 ///
37 /// # Panics
38 /// Panics if the [`Float`] is not an integer and `rm` is `Exact`, or if the [`Float`] is less
39 /// than zero and `rm` is not `Down`, `Ceiling`, or `Nearest`, or if the [`Float`] is NaN or
40 /// $\infty$.
41 ///
42 /// # Examples
43 /// ```
44 /// use malachite_base::num::basic::traits::NegativeInfinity;
45 /// use malachite_base::num::conversion::traits::RoundingFrom;
46 /// use malachite_base::rounding_modes::RoundingMode::*;
47 /// use malachite_base::strings::ToDebugString;
48 /// use malachite_float::Float;
49 /// use malachite_nz::natural::Natural;
50 ///
51 /// assert_eq!(
52 /// Natural::rounding_from(Float::from(1.5), Floor).to_debug_string(),
53 /// "(1, Less)"
54 /// );
55 /// assert_eq!(
56 /// Natural::rounding_from(Float::from(1.5), Ceiling).to_debug_string(),
57 /// "(2, Greater)"
58 /// );
59 /// assert_eq!(
60 /// Natural::rounding_from(Float::from(1.5), Nearest).to_debug_string(),
61 /// "(2, Greater)"
62 /// );
63 ///
64 /// assert_eq!(
65 /// Natural::rounding_from(Float::NEGATIVE_INFINITY, Down).to_debug_string(),
66 /// "(0, Greater)"
67 /// );
68 /// assert_eq!(
69 /// Natural::rounding_from(Float::NEGATIVE_INFINITY, Ceiling).to_debug_string(),
70 /// "(0, Greater)"
71 /// );
72 /// assert_eq!(
73 /// Natural::rounding_from(Float::NEGATIVE_INFINITY, Nearest).to_debug_string(),
74 /// "(0, Greater)"
75 /// );
76 /// ```
77 fn rounding_from(f: Float, rm: RoundingMode) -> (Self, Ordering) {
78 match f {
79 float_either_zero!() => (Self::ZERO, Equal),
80 float_negative_infinity!() => match rm {
81 Ceiling | Down | Nearest => (Self::ZERO, Greater),
82 _ => panic!("Can't convert -Infinity to Natural using {rm}"),
83 },
84 Float(Finite {
85 sign,
86 exponent,
87 significand,
88 ..
89 }) => {
90 if !sign {
91 match rm {
92 Ceiling | Down | Nearest => (Self::ZERO, Greater),
93 _ => panic!("Cannot convert negative number to Natural using {rm}"),
94 }
95 } else if exponent < 0 {
96 match rm {
97 Floor | Down | Nearest => (Self::ZERO, Less),
98 Ceiling | Up => (Self::ONE, Greater),
99 Exact => panic!("Cannot convert Float to Natural using {rm}"),
100 }
101 } else {
102 let sb = significand_bits(&significand);
103 let eb = u64::from(exponent.unsigned_abs());
104 if sb >= eb {
105 significand.shr_round(sb - eb, rm)
106 } else {
107 (significand << (eb - sb), Equal)
108 }
109 }
110 }
111 _ => panic!("Can't convert {f} to Natural using {rm}"),
112 }
113 }
114}
115
116impl RoundingFrom<&Float> for Natural {
117 /// Converts a [`Float`] to a [`Natural`], using a specified [`RoundingMode`] and taking the
118 /// [`Float`] by reference. An [`Ordering`] is also returned, indicating whether the returned
119 /// value is less than, equal to, or greater than the original value.
120 ///
121 /// If the [`Float`] is negative (including $-\infty$), then it will be rounded to zero when the
122 /// [`RoundingMode`] is `Ceiling`, `Down`, or `Nearest`. Otherwise, this function will panic.
123 ///
124 /// If the [`Float`] is NaN or $\infty$, the function will panic regardless of the rounding
125 /// mode.
126 ///
127 /// # Worst-case complexity
128 /// $T(n) = O(n)$
129 ///
130 /// $M(n) = O(n)$
131 ///
132 /// where $T$ is time, $M$ is additional memory, and $n$ is `f.complexity()`.
133 ///
134 /// # Panics
135 /// Panics if the [`Float`] is not an integer and `rm` is `Exact`, or if the [`Float`] is less
136 /// than zero and `rm` is not `Down`, `Ceiling`, or `Nearest`, or if the [`Float`] is NaN or
137 /// $\infty$.
138 ///
139 /// # Examples
140 /// ```
141 /// use malachite_base::num::basic::traits::NegativeInfinity;
142 /// use malachite_base::num::conversion::traits::RoundingFrom;
143 /// use malachite_base::rounding_modes::RoundingMode::*;
144 /// use malachite_base::strings::ToDebugString;
145 /// use malachite_float::Float;
146 /// use malachite_nz::natural::Natural;
147 ///
148 /// assert_eq!(
149 /// Natural::rounding_from(&Float::from(1.5), Floor).to_debug_string(),
150 /// "(1, Less)"
151 /// );
152 /// assert_eq!(
153 /// Natural::rounding_from(&Float::from(1.5), Ceiling).to_debug_string(),
154 /// "(2, Greater)"
155 /// );
156 /// assert_eq!(
157 /// Natural::rounding_from(&Float::from(1.5), Nearest).to_debug_string(),
158 /// "(2, Greater)"
159 /// );
160 ///
161 /// assert_eq!(
162 /// Natural::rounding_from(&Float::NEGATIVE_INFINITY, Down).to_debug_string(),
163 /// "(0, Greater)"
164 /// );
165 /// assert_eq!(
166 /// Natural::rounding_from(&Float::NEGATIVE_INFINITY, Ceiling).to_debug_string(),
167 /// "(0, Greater)"
168 /// );
169 /// assert_eq!(
170 /// Natural::rounding_from(&Float::NEGATIVE_INFINITY, Nearest).to_debug_string(),
171 /// "(0, Greater)"
172 /// );
173 /// ```
174 fn rounding_from(f: &Float, rm: RoundingMode) -> (Self, Ordering) {
175 match f {
176 float_either_zero!() => (Self::ZERO, Equal),
177 float_negative_infinity!() => match rm {
178 Ceiling | Down | Nearest => (Self::ZERO, Greater),
179 _ => panic!("Can't convert -Infinity to Natural using {rm}"),
180 },
181 Float(Finite {
182 sign,
183 exponent,
184 significand,
185 ..
186 }) => {
187 if !sign {
188 match rm {
189 Ceiling | Down | Nearest => (Self::ZERO, Greater),
190 _ => panic!("Cannot convert -Infinity to Natural using {rm}"),
191 }
192 } else if *exponent < 0 {
193 match rm {
194 Floor | Down | Nearest => (Self::ZERO, Less),
195 Ceiling | Up => (Self::ONE, Greater),
196 Exact => panic!("Cannot convert Float to Natural using {rm}"),
197 }
198 } else {
199 let sb = significand_bits(significand);
200 let eb = u64::from(exponent.unsigned_abs());
201 if sb >= eb {
202 significand.shr_round(sb - eb, rm)
203 } else {
204 (significand << (eb - sb), Equal)
205 }
206 }
207 }
208 _ => panic!("Can't convert {f} to Natural using {rm}"),
209 }
210 }
211}
212
213impl TryFrom<Float> for Natural {
214 type Error = UnsignedFromFloatError;
215
216 /// Converts a [`Float`] to a [`Natural`], taking the [`Float`] by value. If the [`Float`] is
217 /// not equal to a non-negative integer, an error is returned.
218 ///
219 /// Both positive and negative zero convert to a [`Natural`] zero.
220 ///
221 /// # Worst-case complexity
222 /// $T(n) = O(n)$
223 ///
224 /// $M(n) = O(n)$
225 ///
226 /// where $T$ is time, $M$ is additional memory, and $n$ is `f.complexity()`.
227 ///
228 /// # Examples
229 /// ```
230 /// use malachite_base::num::basic::traits::{Infinity, NaN, Zero};
231 /// use malachite_base::num::conversion::from::UnsignedFromFloatError::*;
232 /// use malachite_float::Float;
233 /// use malachite_nz::natural::Natural;
234 ///
235 /// assert_eq!(Natural::try_from(Float::ZERO).unwrap(), 0);
236 /// assert_eq!(Natural::try_from(Float::from(123.0)).unwrap(), 123);
237 ///
238 /// assert_eq!(Natural::try_from(Float::from(-123.0)), Err(FloatNegative));
239 /// assert_eq!(
240 /// Natural::try_from(Float::from(1.5)),
241 /// Err(FloatNonIntegerOrOutOfRange)
242 /// );
243 /// assert_eq!(Natural::try_from(Float::INFINITY), Err(FloatInfiniteOrNan));
244 /// assert_eq!(Natural::try_from(Float::NAN), Err(FloatInfiniteOrNan));
245 /// ```
246 fn try_from(f: Float) -> Result<Self, Self::Error> {
247 match f {
248 float_either_zero!() => Ok(Self::ZERO),
249 Float(Finite {
250 sign,
251 exponent,
252 significand,
253 ..
254 }) => {
255 if !sign {
256 Err(UnsignedFromFloatError::FloatNegative)
257 } else if exponent <= 0 {
258 Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange)
259 } else {
260 let sb = significand_bits(&significand);
261 let eb = u64::from(exponent.unsigned_abs());
262 if sb >= eb {
263 let bits = sb - eb;
264 if significand.divisible_by_power_of_2(bits) {
265 Ok(significand >> bits)
266 } else {
267 Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange)
268 }
269 } else {
270 Ok(significand << (eb - sb))
271 }
272 }
273 }
274 _ => Err(UnsignedFromFloatError::FloatInfiniteOrNan),
275 }
276 }
277}
278
279impl TryFrom<&Float> for Natural {
280 type Error = UnsignedFromFloatError;
281
282 /// Converts a [`Float`] to a [`Natural`], taking the [`Float`] by reference. If the [`Float`]
283 /// is not equal to a non-negative integer, an error is returned.
284 ///
285 /// Both positive and negative zero convert to a [`Natural`] zero.
286 ///
287 /// # Worst-case complexity
288 /// $T(n) = O(n)$
289 ///
290 /// $M(n) = O(n)$
291 ///
292 /// where $T$ is time, $M$ is additional memory, and $n$ is `f.complexity()`.
293 ///
294 /// # Examples
295 /// ```
296 /// use malachite_base::num::basic::traits::{Infinity, NaN, Zero};
297 /// use malachite_base::num::conversion::from::UnsignedFromFloatError::*;
298 /// use malachite_float::Float;
299 /// use malachite_nz::natural::Natural;
300 ///
301 /// assert_eq!(Natural::try_from(&Float::ZERO).unwrap(), 0);
302 /// assert_eq!(Natural::try_from(&Float::from(123.0)).unwrap(), 123);
303 ///
304 /// assert_eq!(Natural::try_from(&Float::from(-123.0)), Err(FloatNegative));
305 /// assert_eq!(
306 /// Natural::try_from(&Float::from(1.5)),
307 /// Err(FloatNonIntegerOrOutOfRange)
308 /// );
309 /// assert_eq!(Natural::try_from(&Float::INFINITY), Err(FloatInfiniteOrNan));
310 /// assert_eq!(Natural::try_from(&Float::NAN), Err(FloatInfiniteOrNan));
311 /// ```
312 fn try_from(f: &Float) -> Result<Self, Self::Error> {
313 match f {
314 float_either_zero!() => Ok(Self::ZERO),
315 Float(Finite {
316 sign,
317 exponent,
318 significand,
319 ..
320 }) => {
321 if !*sign {
322 Err(UnsignedFromFloatError::FloatNegative)
323 } else if *exponent <= 0 {
324 Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange)
325 } else {
326 let sb = significand_bits(significand);
327 let eb = u64::from(exponent.unsigned_abs());
328 if sb >= eb {
329 let bits = sb - eb;
330 if significand.divisible_by_power_of_2(bits) {
331 Ok(significand >> bits)
332 } else {
333 Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange)
334 }
335 } else {
336 Ok(significand << (eb - sb))
337 }
338 }
339 }
340 _ => Err(UnsignedFromFloatError::FloatInfiniteOrNan),
341 }
342 }
343}
344
345impl ConvertibleFrom<&Float> for Natural {
346 /// Determines whether a [`Float`] can be converted to a [`Natural`] (when the [`Float`] is
347 /// non-negative and an integer), taking the [`Float`] by reference.
348 ///
349 /// Both positive and negative zero are convertible to a [`Natural`]. (Although negative zero is
350 /// nominally negative, the real number it represents is zero, which is not negative.)
351 ///
352 /// # Worst-case complexity
353 /// $T(n) = O(n)$
354 ///
355 /// $M(n) = O(n)$
356 ///
357 /// where $T$ is time, $M$ is additional memory, and $n$ is `f.significant_bits()`.
358 ///
359 /// # Examples
360 /// ```
361 /// use malachite_base::num::basic::traits::{Infinity, NaN, Zero};
362 /// use malachite_base::num::conversion::traits::ConvertibleFrom;
363 /// use malachite_float::Float;
364 /// use malachite_nz::natural::Natural;
365 ///
366 /// assert_eq!(Natural::convertible_from(&Float::ZERO), true);
367 /// assert_eq!(Natural::convertible_from(&Float::from(123.0)), true);
368 ///
369 /// assert_eq!(Natural::convertible_from(&Float::from(-123.0)), false);
370 /// assert_eq!(Natural::convertible_from(&Float::from(1.5)), false);
371 /// assert_eq!(Natural::convertible_from(&Float::INFINITY), false);
372 /// assert_eq!(Natural::convertible_from(&Float::NAN), false);
373 /// ```
374 fn convertible_from(f: &Float) -> bool {
375 match f {
376 float_either_zero!() => true,
377 Float(Finite {
378 sign,
379 exponent,
380 significand,
381 ..
382 }) => {
383 *sign && *exponent > 0 && {
384 let sb = significand_bits(significand);
385 let eb = u64::from(exponent.unsigned_abs());
386 sb < eb || significand.divisible_by_power_of_2(sb - eb)
387 }
388 }
389 _ => false,
390 }
391 }
392}