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);