malachite_q/arithmetic/shr.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::ops::{Shl, ShlAssign, Shr, ShrAssign};
11use malachite_base::num::arithmetic::traits::UnsignedAbs;
12use malachite_base::num::basic::traits::Zero;
13use malachite_base::num::conversion::traits::ExactFrom;
14
15fn shr_unsigned_assign<T>(x: &mut Rational, bits: T)
16where
17 u64: TryFrom<T>,
18{
19 if *x == 0u32 {
20 return;
21 }
22 let numerator_zeros = x.numerator.trailing_zeros().unwrap();
23 let bits_64 = u64::exact_from(bits);
24 if numerator_zeros >= bits_64 {
25 x.numerator >>= bits_64;
26 } else {
27 x.denominator <<= bits_64 - numerator_zeros;
28 x.numerator >>= numerator_zeros;
29 }
30}
31
32fn shr_unsigned_ref<T>(x: &Rational, bits: T) -> Rational
33where
34 u64: TryFrom<T>,
35{
36 if *x == 0u32 {
37 return x.clone();
38 }
39 let numerator_zeros = x.numerator.trailing_zeros().unwrap();
40 let bits_64 = u64::exact_from(bits);
41 if numerator_zeros >= bits_64 {
42 Rational {
43 sign: x.sign,
44 numerator: &x.numerator >> bits_64,
45 denominator: x.denominator.clone(),
46 }
47 } else {
48 Rational {
49 sign: x.sign,
50 numerator: &x.numerator >> numerator_zeros,
51 denominator: &x.denominator << (bits_64 - numerator_zeros),
52 }
53 }
54}
55
56macro_rules! impl_shr_unsigned {
57 ($t:ident) => {
58 impl Shr<$t> for Rational {
59 type Output = Rational;
60
61 /// Right-shifts a [`Rational`] (divides it by a power of 2), taking it by value.
62 ///
63 /// $$
64 /// f(x, k) = \frac{x}{2^k}.
65 /// $$
66 ///
67 /// # Worst-case complexity
68 /// $T(n, m) = O(n + m)$
69 ///
70 /// $M(n, m) = O(n + m)$
71 ///
72 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
73 /// $m$ is `max(bits, 0)`.
74 ///
75 /// See [here](super::shr#shr).
76 #[inline]
77 fn shr(mut self, bits: $t) -> Rational {
78 self >>= bits;
79 self
80 }
81 }
82
83 impl Shr<$t> for &Rational {
84 type Output = Rational;
85
86 /// Right-shifts a [`Rational`] (divides it by a power of 2), taking it by reference.
87 ///
88 /// $$
89 /// f(x, k) = \frac{x}{2^k}.
90 /// $$
91 ///
92 /// # Worst-case complexity
93 /// $T(n, m) = O(n + m)$
94 ///
95 /// $M(n, m) = O(n + m)$
96 ///
97 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
98 /// $m$ is `max(bits, 0)`.
99 ///
100 /// See [here](super::shr#shr).
101 #[inline]
102 fn shr(self, bits: $t) -> Rational {
103 shr_unsigned_ref(self, bits)
104 }
105 }
106
107 impl ShrAssign<$t> for Rational {
108 /// Right-shifts a [`Rational`] (divides it by a power of 2), in place.
109 ///
110 /// $$
111 /// f(x, k) = \frac{x}{2^k}.
112 /// $$
113 ///
114 /// # Worst-case complexity
115 /// $T(n, m) = O(n + m)$
116 ///
117 /// $M(n, m) = O(n + m)$
118 ///
119 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
120 /// $m$ is `max(bits, 0)`.
121 ///
122 /// See [here](super::shr#shr_assign).
123 #[inline]
124 fn shr_assign(&mut self, bits: $t) {
125 shr_unsigned_assign(self, bits);
126 }
127 }
128 };
129}
130apply_to_unsigneds!(impl_shr_unsigned);
131
132fn shr_signed_ref<'a, U, S: Copy + Ord + UnsignedAbs<Output = U> + Zero>(
133 x: &'a Rational,
134 bits: S,
135) -> Rational
136where
137 &'a Rational: Shl<U, Output = Rational> + Shr<U, Output = Rational>,
138{
139 if bits >= S::ZERO {
140 x >> bits.unsigned_abs()
141 } else {
142 x << bits.unsigned_abs()
143 }
144}
145
146fn shr_assign_signed<U, S: Copy + Ord + UnsignedAbs<Output = U> + Zero>(x: &mut Rational, bits: S)
147where
148 Rational: ShlAssign<U> + ShrAssign<U>,
149{
150 if bits >= S::ZERO {
151 *x >>= bits.unsigned_abs();
152 } else {
153 *x <<= bits.unsigned_abs();
154 }
155}
156
157macro_rules! impl_shr_signed {
158 ($t:ident) => {
159 impl Shr<$t> for Rational {
160 type Output = Rational;
161
162 /// Right-shifts a [`Rational`] (divides it by a power of 2), taking it by value.
163 ///
164 /// $$
165 /// f(x, k) = \frac{x}{2^k}.
166 /// $$
167 ///
168 /// # Worst-case complexity
169 /// $T(n, m) = O(n + m)$
170 ///
171 /// $M(n, m) = O(n + m)$
172 ///
173 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
174 /// $m$ is `max(bits, 0)`.
175 ///
176 /// See [here](super::shr#shr).
177 #[inline]
178 fn shr(mut self, bits: $t) -> Rational {
179 self >>= bits;
180 self
181 }
182 }
183
184 impl Shr<$t> for &Rational {
185 type Output = Rational;
186
187 /// Right-shifts a [`Rational`] (divides it by a power of 2), taking it by reference.
188 ///
189 /// $$
190 /// f(x, k) = \frac{x}{2^k}.
191 /// $$
192 ///
193 /// # Worst-case complexity
194 /// $T(n, m) = O(n + m)$
195 ///
196 /// $M(n, m) = O(n + m)$
197 ///
198 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
199 /// $m$ is `max(bits, 0)`.
200 ///
201 /// See [here](super::shr#shr).
202 #[inline]
203 fn shr(self, bits: $t) -> Rational {
204 shr_signed_ref(self, bits)
205 }
206 }
207
208 impl ShrAssign<$t> for Rational {
209 /// Right-shifts a [`Rational`] (divides it by a power of 2), in reference.
210 ///
211 /// $$
212 /// f(x, k) = \frac{x}{2^k}.
213 /// $$
214 ///
215 /// # Worst-case complexity
216 /// $T(n, m) = O(n + m)$
217 ///
218 /// $M(n, m) = O(n + m)$
219 ///
220 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
221 /// $m$ is `max(bits, 0)`.
222 ///
223 /// See [here](super::shr#shr_assign).
224 #[inline]
225 fn shr_assign(&mut self, bits: $t) {
226 shr_assign_signed(self, bits)
227 }
228 }
229 };
230}
231apply_to_signeds!(impl_shr_signed);