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