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