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