malachite_float/conversion/
rational_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 malachite_base::num::basic::traits::Zero as ZeroTrait;
12use malachite_base::num::conversion::traits::ConvertibleFrom;
13use malachite_nz::integer::Integer;
14use malachite_q::Rational;
15
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub struct RationalFromFloatError;
18
19impl TryFrom<Float> for Rational {
20    type Error = RationalFromFloatError;
21
22    /// Converts a [`Float`] to a [`Rational`], taking the [`Float`] by value. If the [`Float`] is
23    /// not finite, an error is returned.
24    ///
25    /// # Worst-case complexity
26    /// $T(n) = O(n)$
27    ///
28    /// $M(n) = O(n)$
29    ///
30    /// where $T$ is time, $M$ is additional memory, and $n$ is `x.complexity()`.
31    ///
32    /// # Examples
33    /// ```
34    /// use malachite_base::num::basic::traits::{Infinity, NaN, Zero};
35    /// use malachite_float::conversion::rational_from_float::RationalFromFloatError;
36    /// use malachite_float::Float;
37    /// use malachite_q::Rational;
38    ///
39    /// assert_eq!(Rational::try_from(Float::ZERO).unwrap(), 0);
40    /// assert_eq!(
41    ///     Rational::try_from(Float::from(1.5)).unwrap().to_string(),
42    ///     "3/2"
43    /// );
44    /// assert_eq!(
45    ///     Rational::try_from(Float::from(-1.5)).unwrap().to_string(),
46    ///     "-3/2"
47    /// );
48    ///
49    /// assert_eq!(
50    ///     Rational::try_from(Float::INFINITY),
51    ///     Err(RationalFromFloatError)
52    /// );
53    /// assert_eq!(Rational::try_from(Float::NAN), Err(RationalFromFloatError));
54    /// ```
55    fn try_from(x: Float) -> Result<Self, Self::Error> {
56        match x {
57            float_either_zero!() => Ok(Self::ZERO),
58            Float(Finite {
59                sign,
60                exponent,
61                significand,
62                ..
63            }) => {
64                let bits = significand_bits(&significand);
65                Ok(Self::from(Integer::from_sign_and_abs(sign, significand))
66                    << (i128::from(exponent) - i128::from(bits)))
67            }
68            _ => Err(RationalFromFloatError),
69        }
70    }
71}
72
73impl TryFrom<&Float> for Rational {
74    type Error = RationalFromFloatError;
75
76    /// Converts a [`Float`] to a [`Rational`], taking the [`Float`] by reference. If the [`Float`]
77    /// is not finite, an error is returned.
78    ///
79    /// # Worst-case complexity
80    /// $T(n) = O(n)$
81    ///
82    /// $M(n) = O(n)$
83    ///
84    /// where $T$ is time, $M$ is additional memory, and $n$ is `x.complexity()`.
85    ///
86    /// # Examples
87    /// ```
88    /// use malachite_base::num::basic::traits::{Infinity, NaN, Zero};
89    /// use malachite_float::conversion::rational_from_float::RationalFromFloatError;
90    /// use malachite_float::Float;
91    /// use malachite_q::Rational;
92    ///
93    /// assert_eq!(Rational::try_from(&Float::ZERO).unwrap(), 0);
94    /// assert_eq!(
95    ///     Rational::try_from(&Float::from(1.5)).unwrap().to_string(),
96    ///     "3/2"
97    /// );
98    /// assert_eq!(
99    ///     Rational::try_from(&Float::from(-1.5)).unwrap().to_string(),
100    ///     "-3/2"
101    /// );
102    ///
103    /// assert_eq!(
104    ///     Rational::try_from(&Float::INFINITY),
105    ///     Err(RationalFromFloatError)
106    /// );
107    /// assert_eq!(Rational::try_from(&Float::NAN), Err(RationalFromFloatError));
108    /// ```
109    fn try_from(x: &Float) -> Result<Self, Self::Error> {
110        match x {
111            float_either_zero!() => Ok(Self::ZERO),
112            Float(Finite {
113                sign,
114                exponent,
115                significand,
116                ..
117            }) => {
118                let bits = significand_bits(significand);
119                Ok(
120                    Self::from(Integer::from_sign_and_abs_ref(*sign, significand))
121                        << (i128::from(*exponent) - i128::from(bits)),
122                )
123            }
124            _ => Err(RationalFromFloatError),
125        }
126    }
127}
128
129impl ConvertibleFrom<&Float> for Rational {
130    /// Determines whether a [`Float`] can be converted to a [`Rational`] (which is when the
131    /// [`Float`] is finite), taking the [`Float`] by reference.
132    ///
133    /// # Worst-case complexity
134    /// Constant time and additional memory.
135    ///
136    /// # Examples
137    /// ```
138    /// use malachite_base::num::basic::traits::{Infinity, NaN, Zero};
139    /// use malachite_base::num::conversion::traits::ConvertibleFrom;
140    /// use malachite_float::Float;
141    /// use malachite_q::Rational;
142    ///
143    /// assert_eq!(Rational::convertible_from(&Float::ZERO), true);
144    /// assert_eq!(Rational::convertible_from(&Float::from(123.0)), true);
145    /// assert_eq!(Rational::convertible_from(&Float::from(-123.0)), true);
146    /// assert_eq!(Rational::convertible_from(&Float::from(1.5)), true);
147    ///
148    /// assert_eq!(Rational::convertible_from(&Float::INFINITY), false);
149    /// assert_eq!(Rational::convertible_from(&Float::NAN), false);
150    /// ```
151    #[inline]
152    fn convertible_from(x: &Float) -> bool {
153        x.is_finite()
154    }
155}