malachite_q/conversion/integer_from_rational.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::Rational;
10use core::cmp::Ordering;
11use malachite_base::num::arithmetic::traits::DivRound;
12use malachite_base::num::conversion::traits::{ConvertibleFrom, RoundingFrom};
13use malachite_base::rounding_modes::RoundingMode;
14use malachite_nz::integer::Integer;
15
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub struct IntegerFromRationalError;
18
19impl TryFrom<Rational> for Integer {
20 type Error = IntegerFromRationalError;
21
22 /// Converts a [`Rational`] to an [`Integer`], taking the [`Rational`] by value. If the
23 /// [`Rational`] is not an integer, an error is returned.
24 ///
25 /// # Worst-case complexity
26 /// Constant time and additional memory.
27 ///
28 /// # Examples
29 /// ```
30 /// use malachite_nz::integer::Integer;
31 /// use malachite_q::conversion::integer_from_rational::IntegerFromRationalError;
32 /// use malachite_q::Rational;
33 ///
34 /// assert_eq!(Integer::try_from(Rational::from(123)).unwrap(), 123);
35 /// assert_eq!(Integer::try_from(Rational::from(-123)).unwrap(), -123);
36 /// assert_eq!(
37 /// Integer::try_from(Rational::from_signeds(22, 7)),
38 /// Err(IntegerFromRationalError)
39 /// );
40 /// ```
41 fn try_from(x: Rational) -> Result<Integer, Self::Error> {
42 if x.denominator == 1u32 {
43 Ok(Integer::from_sign_and_abs(x.sign, x.numerator))
44 } else {
45 Err(IntegerFromRationalError)
46 }
47 }
48}
49
50impl TryFrom<&Rational> for Integer {
51 type Error = IntegerFromRationalError;
52
53 /// Converts a [`Rational`] to an [`Integer`], taking the [`Rational`] by reference. If the
54 /// [`Rational`] is not an integer, an error is returned.
55 ///
56 /// # Worst-case complexity
57 /// $T(n) = O(n)$
58 ///
59 /// $M(n) = O(n)$
60 ///
61 /// where $T$ is time, $M$ is additional memory, and $n$ is `x.significant_bits()`.
62 ///
63 /// # Examples
64 /// ```
65 /// use malachite_nz::integer::Integer;
66 /// use malachite_q::conversion::integer_from_rational::IntegerFromRationalError;
67 /// use malachite_q::Rational;
68 ///
69 /// assert_eq!(Integer::try_from(&Rational::from(123)).unwrap(), 123);
70 /// assert_eq!(Integer::try_from(&Rational::from(-123)).unwrap(), -123);
71 /// assert_eq!(
72 /// Integer::try_from(&Rational::from_signeds(22, 7)),
73 /// Err(IntegerFromRationalError)
74 /// );
75 /// ```
76 fn try_from(x: &Rational) -> Result<Integer, Self::Error> {
77 if x.denominator == 1u32 {
78 Ok(Integer::from_sign_and_abs_ref(x.sign, &x.numerator))
79 } else {
80 Err(IntegerFromRationalError)
81 }
82 }
83}
84
85impl ConvertibleFrom<&Rational> for Integer {
86 /// Determines whether a [`Rational`] can be converted to an [`Integer`], taking the
87 /// [`Rational`] by reference.
88 ///
89 /// # Worst-case complexity
90 /// Constant time and additional memory.
91 ///
92 /// # Examples
93 /// ```
94 /// use malachite_base::num::conversion::traits::ConvertibleFrom;
95 /// use malachite_nz::integer::Integer;
96 /// use malachite_q::Rational;
97 ///
98 /// assert_eq!(Integer::convertible_from(&Rational::from(123)), true);
99 /// assert_eq!(Integer::convertible_from(&Rational::from(-123)), true);
100 /// assert_eq!(
101 /// Integer::convertible_from(&Rational::from_signeds(22, 7)),
102 /// false
103 /// );
104 /// ```
105 #[inline]
106 fn convertible_from(x: &Rational) -> bool {
107 x.denominator == 1u32
108 }
109}
110
111impl RoundingFrom<Rational> for Integer {
112 /// Converts a [`Rational`] to an [`Integer`], using a specified [`RoundingMode`] and taking the
113 /// [`Rational`] by value. An [`Ordering`] is also returned, indicating whether the returned
114 /// value is less than, equal to, or greater than the original value.
115 ///
116 /// # Worst-case complexity
117 /// $T(n) = O(n \log n \log\log n)$
118 ///
119 /// $M(n) = O(n \log n)$
120 ///
121 /// where $T$ is time, $M$ is additional memory, and $n$ is `x.significant_bits()`.
122 ///
123 /// # Panics
124 /// Panics if the [`Rational`] is not an integer and `rm` is `Exact`.
125 ///
126 /// # Examples
127 /// ```
128 /// use malachite_base::num::conversion::traits::RoundingFrom;
129 /// use malachite_base::rounding_modes::RoundingMode::*;
130 /// use malachite_base::strings::ToDebugString;
131 /// use malachite_nz::integer::Integer;
132 /// use malachite_q::Rational;
133 ///
134 /// assert_eq!(
135 /// Integer::rounding_from(Rational::from(123), Exact).to_debug_string(),
136 /// "(123, Equal)"
137 /// );
138 /// assert_eq!(
139 /// Integer::rounding_from(Rational::from(-123), Exact).to_debug_string(),
140 /// "(-123, Equal)"
141 /// );
142 ///
143 /// assert_eq!(
144 /// Integer::rounding_from(Rational::from_signeds(22, 7), Floor).to_debug_string(),
145 /// "(3, Less)"
146 /// );
147 /// assert_eq!(
148 /// Integer::rounding_from(Rational::from_signeds(22, 7), Down).to_debug_string(),
149 /// "(3, Less)"
150 /// );
151 /// assert_eq!(
152 /// Integer::rounding_from(Rational::from_signeds(22, 7), Ceiling).to_debug_string(),
153 /// "(4, Greater)"
154 /// );
155 /// assert_eq!(
156 /// Integer::rounding_from(Rational::from_signeds(22, 7), Up).to_debug_string(),
157 /// "(4, Greater)"
158 /// );
159 /// assert_eq!(
160 /// Integer::rounding_from(Rational::from_signeds(22, 7), Nearest).to_debug_string(),
161 /// "(3, Less)"
162 /// );
163 ///
164 /// assert_eq!(
165 /// Integer::rounding_from(Rational::from_signeds(-22, 7), Floor).to_debug_string(),
166 /// "(-4, Less)"
167 /// );
168 /// assert_eq!(
169 /// Integer::rounding_from(Rational::from_signeds(-22, 7), Down).to_debug_string(),
170 /// "(-3, Greater)"
171 /// );
172 /// assert_eq!(
173 /// Integer::rounding_from(Rational::from_signeds(-22, 7), Ceiling).to_debug_string(),
174 /// "(-3, Greater)"
175 /// );
176 /// assert_eq!(
177 /// Integer::rounding_from(Rational::from_signeds(-22, 7), Up).to_debug_string(),
178 /// "(-4, Less)"
179 /// );
180 /// assert_eq!(
181 /// Integer::rounding_from(Rational::from_signeds(-22, 7), Nearest).to_debug_string(),
182 /// "(-3, Greater)"
183 /// );
184 /// ```
185 fn rounding_from(x: Rational, rm: RoundingMode) -> (Integer, Ordering) {
186 let s = x.sign;
187 let (n, o) = x
188 .numerator
189 .div_round(x.denominator, if s { rm } else { -rm });
190 (
191 Integer::from_sign_and_abs(x.sign, n),
192 if s { o } else { o.reverse() },
193 )
194 }
195}
196
197impl RoundingFrom<&Rational> for Integer {
198 /// Converts a [`Rational`] to an [`Integer`], using a specified [`RoundingMode`] and taking the
199 /// [`Rational`] by reference. An [`Ordering`] is also returned, indicating whether the returned
200 /// value is less than, equal to, or greater than the original value.
201 ///
202 /// # Worst-case complexity
203 /// $T(n) = O(n \log n \log\log n)$
204 ///
205 /// $M(n) = O(n \log n)$
206 ///
207 /// where $T$ is time, $M$ is additional memory, and $n$ is `x.significant_bits()`.
208 ///
209 /// # Panics
210 /// Panics if the [`Rational`] is not an integer and `rm` is `Exact`.
211 ///
212 /// # Examples
213 /// ```
214 /// use malachite_base::num::conversion::traits::RoundingFrom;
215 /// use malachite_base::rounding_modes::RoundingMode::*;
216 /// use malachite_base::strings::ToDebugString;
217 /// use malachite_nz::integer::Integer;
218 /// use malachite_q::Rational;
219 ///
220 /// assert_eq!(
221 /// Integer::rounding_from(&Rational::from(123), Exact).to_debug_string(),
222 /// "(123, Equal)"
223 /// );
224 /// assert_eq!(
225 /// Integer::rounding_from(&Rational::from(-123), Exact).to_debug_string(),
226 /// "(-123, Equal)"
227 /// );
228 ///
229 /// assert_eq!(
230 /// Integer::rounding_from(&Rational::from_signeds(22, 7), Floor).to_debug_string(),
231 /// "(3, Less)"
232 /// );
233 /// assert_eq!(
234 /// Integer::rounding_from(&Rational::from_signeds(22, 7), Down).to_debug_string(),
235 /// "(3, Less)"
236 /// );
237 /// assert_eq!(
238 /// Integer::rounding_from(&Rational::from_signeds(22, 7), Ceiling).to_debug_string(),
239 /// "(4, Greater)"
240 /// );
241 /// assert_eq!(
242 /// Integer::rounding_from(&Rational::from_signeds(22, 7), Up).to_debug_string(),
243 /// "(4, Greater)"
244 /// );
245 /// assert_eq!(
246 /// Integer::rounding_from(&Rational::from_signeds(22, 7), Nearest).to_debug_string(),
247 /// "(3, Less)"
248 /// );
249 ///
250 /// assert_eq!(
251 /// Integer::rounding_from(Rational::from_signeds(-22, 7), Floor).to_debug_string(),
252 /// "(-4, Less)"
253 /// );
254 /// assert_eq!(
255 /// Integer::rounding_from(Rational::from_signeds(-22, 7), Down).to_debug_string(),
256 /// "(-3, Greater)"
257 /// );
258 /// assert_eq!(
259 /// Integer::rounding_from(Rational::from_signeds(-22, 7), Ceiling).to_debug_string(),
260 /// "(-3, Greater)"
261 /// );
262 /// assert_eq!(
263 /// Integer::rounding_from(Rational::from_signeds(-22, 7), Up).to_debug_string(),
264 /// "(-4, Less)"
265 /// );
266 /// assert_eq!(
267 /// Integer::rounding_from(Rational::from_signeds(-22, 7), Nearest).to_debug_string(),
268 /// "(-3, Greater)"
269 /// );
270 /// ```
271 fn rounding_from(x: &Rational, rm: RoundingMode) -> (Integer, Ordering) {
272 let (n, o) = (&x.numerator).div_round(&x.denominator, if x.sign { rm } else { -rm });
273 (
274 Integer::from_sign_and_abs(x.sign, n),
275 if x.sign { o } else { o.reverse() },
276 )
277 }
278}