malachite_q/arithmetic/floor.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::mem::swap;
11use malachite_base::num::arithmetic::traits::{DivRound, DivRoundAssign, Floor, FloorAssign};
12use malachite_base::num::basic::traits::One;
13use malachite_base::rounding_modes::RoundingMode::*;
14use malachite_nz::integer::Integer;
15use malachite_nz::natural::Natural;
16
17impl Floor for Rational {
18 type Output = Integer;
19
20 /// Finds the floor of a [`Rational`], taking the [`Rational`] by value.
21 ///
22 /// $$
23 /// f(x) = \lfloor x \rfloor.
24 /// $$
25 ///
26 /// # Worst-case complexity
27 /// $T(n) = O(n \log n \log\log n)$
28 ///
29 /// $M(n) = O(n \log n)$
30 ///
31 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
32 /// other.significant_bits())`.
33 ///
34 /// # Examples
35 /// ```
36 /// use malachite_base::num::arithmetic::traits::Floor;
37 /// use malachite_base::num::basic::traits::Zero;
38 /// use malachite_q::Rational;
39 ///
40 /// assert_eq!(Rational::ZERO.floor(), 0);
41 /// assert_eq!(Rational::from_signeds(22, 7).floor(), 3);
42 /// assert_eq!(Rational::from_signeds(-22, 7).floor(), -4);
43 /// ```
44 fn floor(self) -> Integer {
45 if self.sign {
46 Integer::from(self.numerator / self.denominator)
47 } else {
48 Integer::from_sign_and_abs(false, self.numerator.div_round(self.denominator, Ceiling).0)
49 }
50 }
51}
52
53impl Floor for &Rational {
54 type Output = Integer;
55
56 /// Finds the floor of a [`Rational`], taking the [`Rational`] by reference.
57 ///
58 /// $$
59 /// f(x) = \lfloor x \rfloor.
60 /// $$
61 ///
62 /// # Worst-case complexity
63 /// $T(n) = O(n \log n \log\log n)$
64 ///
65 /// $M(n) = O(n \log n)$
66 ///
67 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
68 /// other.significant_bits())`.
69 ///
70 /// # Examples
71 /// ```
72 /// use malachite_base::num::arithmetic::traits::Floor;
73 /// use malachite_base::num::basic::traits::Zero;
74 /// use malachite_q::Rational;
75 ///
76 /// assert_eq!((&Rational::ZERO).floor(), 0);
77 /// assert_eq!((&Rational::from_signeds(22, 7)).floor(), 3);
78 /// assert_eq!((&Rational::from_signeds(-22, 7)).floor(), -4);
79 /// ```
80 fn floor(self) -> Integer {
81 if self.sign {
82 Integer::from(&self.numerator / &self.denominator)
83 } else {
84 Integer::from_sign_and_abs(
85 false,
86 (&self.numerator).div_round(&self.denominator, Ceiling).0,
87 )
88 }
89 }
90}
91
92impl FloorAssign for Rational {
93 /// Replaces a [`Rational`] with its floor.
94 ///
95 /// $$
96 /// x \gets \lfloor x \rfloor.
97 /// $$
98 ///
99 /// # Worst-case complexity
100 /// $T(n) = O(n \log n \log\log n)$
101 ///
102 /// $M(n) = O(n \log n)$
103 ///
104 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
105 /// other.significant_bits())`.
106 ///
107 /// # Examples
108 /// ```
109 /// use malachite_base::num::arithmetic::traits::FloorAssign;
110 /// use malachite_base::num::basic::traits::Zero;
111 /// use malachite_q::Rational;
112 ///
113 /// let mut x = Rational::ZERO;
114 /// x.floor_assign();
115 /// assert_eq!(x, 0);
116 ///
117 /// let mut x = Rational::from_signeds(22, 7);
118 /// x.floor_assign();
119 /// assert_eq!(x, 3);
120 ///
121 /// let mut x = Rational::from_signeds(-22, 7);
122 /// x.floor_assign();
123 /// assert_eq!(x, -4);
124 /// ```
125 fn floor_assign(&mut self) {
126 let mut d = Natural::ONE;
127 swap(&mut self.denominator, &mut d);
128 if self.sign {
129 self.numerator /= d;
130 } else {
131 self.numerator.div_round_assign(d, Ceiling);
132 if !self.sign && self.numerator == 0 {
133 self.sign = true;
134 }
135 }
136 }
137}