malachite_nz/natural/arithmetic/shl.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5// Copyright © 1991, 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
6//
7// This file is part of Malachite.
8//
9// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
10// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
11// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
12
13use crate::natural::InnerNatural::{Large, Small};
14use crate::natural::{Natural, bit_to_limb_count_floor};
15use crate::platform::Limb;
16use alloc::vec::Vec;
17use core::ops::{Shl, ShlAssign, Shr, ShrAssign};
18use malachite_base::num::arithmetic::traits::{ArithmeticCheckedShl, UnsignedAbs};
19use malachite_base::num::basic::integers::PrimitiveInt;
20use malachite_base::num::basic::signeds::PrimitiveSigned;
21use malachite_base::num::basic::traits::Zero;
22use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
23use malachite_base::num::conversion::traits::ExactFrom;
24use malachite_base::vecs::vec_pad_left;
25
26// Interpreting a slice of `Limb`s as the limbs (in ascending order) of a `Natural`, returns the
27// limbs of the `Natural` left-shifted by a `Limb`.
28//
29// # Worst-case complexity
30// $T(n, m) = O(n + m)$
31//
32// $M(n, m) = O(n + m)$
33//
34// where $T$ is time, $M$ is additional memory, $n$ is `xs.len()`, and $m$ is `bits / Limb::WIDTH`.
35//
36// This is equivalent to `mpn_lshift` from `mpn/generic/lshift.c`, GMP 6.2.1, where the result is
37// returned.
38pub_crate_test! {limbs_shl(xs: &[Limb], bits: u64) -> Vec<Limb> {
39 let small_bits = bits & Limb::WIDTH_MASK;
40 let mut out = vec![0; bit_to_limb_count_floor(bits)];
41 if small_bits == 0 {
42 out.extend_from_slice(xs);
43 } else {
44 let cobits = Limb::WIDTH - small_bits;
45 let mut remaining_bits = 0;
46 for x in xs {
47 out.push((x << small_bits) | remaining_bits);
48 remaining_bits = x >> cobits;
49 }
50 if remaining_bits != 0 {
51 out.push(remaining_bits);
52 }
53 }
54 out
55}}
56
57// Interpreting a slice of `Limb`s as the limbs (in ascending order) of a `Natural`, writes the
58// limbs of the `Natural` left-shifted by a `Limb` to an output slice. The output slice must be at
59// least as long as the input slice. The `Limb` must be between 1 and `Limb::WIDTH` - 1, inclusive.
60// The carry, or the bits that are shifted past the width of the input slice, is returned.
61//
62// # Worst-case complexity
63// $T(n) = O(n)$
64//
65// $M(n) = O(n)$
66//
67// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
68//
69// # Panics
70// Panics if `out` is shorter than `xs`, `bits` is 0, or `bits` is greater than or equal to
71// `Limb::WIDTH`.
72//
73// This is equivalent to `mpn_lshift` from `mpn/generic/lshift.c`, GMP 6.2.1.
74pub_crate_test! {limbs_shl_to_out(out: &mut [Limb], xs: &[Limb], bits: u64) -> Limb {
75 assert_ne!(bits, 0);
76 assert!(bits < Limb::WIDTH);
77 let cobits = Limb::WIDTH - bits;
78 let mut remaining_bits = 0;
79 for (out, x) in out[..xs.len()].iter_mut().zip(xs.iter()) {
80 *out = (x << bits) | remaining_bits;
81 remaining_bits = x >> cobits;
82 }
83 remaining_bits
84}}
85
86// Interpreting a slice of `Limb`s as the limbs (in ascending order) of a `Natural`, writes the
87// limbs of the `Natural` left-shifted by a `Limb` to the input slice. The `Limb` must be between 1
88// and `Limb::WIDTH` - 1, inclusive. The carry, or the bits that are shifted past the width of the
89// input slice, is returned.
90//
91// # Worst-case complexity
92// $T(n) = O(n)$
93//
94// $M(n) = O(1)$
95//
96// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
97//
98// This is equivalent to `mpn_lshift` from `mpn/generic/lshift.c`, GMP 6.2.1, where `rp == up`.
99pub_crate_test! {limbs_slice_shl_in_place(xs: &mut [Limb], bits: u64) -> Limb {
100 assert_ne!(bits, 0);
101 assert!(bits < Limb::WIDTH);
102 let cobits = Limb::WIDTH - bits;
103 let mut remaining_bits = 0;
104 for x in &mut *xs {
105 let previous_x = *x;
106 *x = (previous_x << bits) | remaining_bits;
107 remaining_bits = previous_x >> cobits;
108 }
109 remaining_bits
110}}
111
112// Interpreting a nonempty `Vec` of `Limb`s as the limbs (in ascending order) of a `Natural`, writes
113// the limbs of the `Natural` left-shifted by a `Limb` to the input `Vec`.
114//
115// # Worst-case complexity
116// $T(n, m) = O(n + m)$
117//
118// $M(n, m) = O(n + m)$
119//
120// # Panics
121// Panics if `xs` is empty.
122//
123// This is equivalent to `mpn_lshift` from `mpn/generic/lshift.c`, GMP 6.2.1, where `rp == up` and
124// the carry is appended to `rp`.
125pub_crate_test! {limbs_vec_shl_in_place(xs: &mut Vec<Limb>, bits: u64) {
126 let small_bits = bits & Limb::WIDTH_MASK;
127 let remaining_bits = if small_bits == 0 {
128 0
129 } else {
130 limbs_slice_shl_in_place(xs, small_bits)
131 };
132 vec_pad_left(xs, bit_to_limb_count_floor(bits), 0);
133 if remaining_bits != 0 {
134 xs.push(remaining_bits);
135 }
136}}
137
138// Interpreting a slice of `Limb`s as the limbs (in ascending order) of a `Natural`, writes the
139// limbs of the `Natural` left-shifted by a `Limb`, and complemented, to an output slice. The output
140// slice must be at least as long as the input slice. The `Limb` must be between 1 and `Limb::WIDTH`
141// - 1, inclusive. The carry, or the bits that are shifted past the width of the input slice, is
142// returned. The carry is not complemented.
143//
144// # Worst-case complexity
145// $T(n) = O(n)$
146//
147// $M(n) = O(1)$
148//
149// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
150//
151// # Panics
152// Panics if `out` is shorter than `xs`, `xs` is empty, `bits` is 0, or `bits` is greater than or
153// equal to `Limb::WIDTH`.
154//
155// This is equivalent to `mpn_lshiftc` from `mpn/generic/lshift.c`, GMP 6.2.1.
156pub_crate_test! {limbs_shl_with_complement_to_out(
157 out: &mut [Limb],
158 xs: &[Limb],
159 bits: u64
160) -> Limb {
161 let n = xs.len();
162 assert_ne!(n, 0);
163 assert_ne!(bits, 0);
164 assert!(bits < Limb::WIDTH);
165 let cobits = Limb::WIDTH - bits;
166 let (xs_last, xs_init) = xs.split_last().unwrap();
167 let remaining_bits = xs_last >> cobits;
168 let mut previous_x = xs_last << bits;
169 let (out_head, out_tail) = out[..n].split_first_mut().unwrap();
170 for (out, x) in out_tail.iter_mut().rev().zip(xs_init.iter().rev()) {
171 *out = !(previous_x | (x >> cobits));
172 previous_x = x << bits;
173 }
174 *out_head = !previous_x;
175 remaining_bits
176}}
177
178fn shl_ref_unsigned<T: PrimitiveUnsigned>(x: &Natural, bits: T) -> Natural
179where
180 u64: ExactFrom<T>,
181 Limb: ArithmeticCheckedShl<T, Output = Limb>,
182{
183 match (x, bits) {
184 (&Natural::ZERO, _) => x.clone(),
185 (_, bits) if bits == T::ZERO => x.clone(),
186 (Natural(Small(small)), bits) => {
187 Natural(if let Some(shifted) = small.arithmetic_checked_shl(bits) {
188 Small(shifted)
189 } else {
190 Large(limbs_shl(&[*small], u64::exact_from(bits)))
191 })
192 }
193 (Natural(Large(limbs)), bits) => Natural(Large(limbs_shl(limbs, u64::exact_from(bits)))),
194 }
195}
196
197fn shl_assign<T: PrimitiveUnsigned>(x: &mut Natural, bits: T)
198where
199 u64: ExactFrom<T>,
200 Limb: ArithmeticCheckedShl<T, Output = Limb>,
201{
202 match (&mut *x, bits) {
203 (&mut Natural::ZERO, _) => {}
204 (_, bits) if bits == T::ZERO => {}
205 (Natural(Small(small)), bits) => {
206 if let Some(shifted) = small.arithmetic_checked_shl(bits) {
207 *small = shifted;
208 } else {
209 *x = Natural(Large(limbs_shl(&[*small], u64::exact_from(bits))));
210 }
211 }
212 (Natural(Large(limbs)), bits) => {
213 limbs_vec_shl_in_place(limbs, u64::exact_from(bits));
214 }
215 }
216}
217
218macro_rules! impl_natural_shl_unsigned {
219 ($t:ident) => {
220 impl Shl<$t> for Natural {
221 type Output = Natural;
222
223 /// Left-shifts a [`Natural`] (multiplies it by a power of 2), taking it by value.
224 ///
225 /// $f(x, k) = x2^k$.
226 ///
227 /// # Worst-case complexity
228 /// $T(n, m) = O(n + m)$
229 ///
230 /// $M(n, m) = O(n + m)$
231 ///
232 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
233 /// $m$ is `bits`.
234 ///
235 /// # Examples
236 /// See [here](super::shl#shl).
237 #[inline]
238 fn shl(mut self, bits: $t) -> Natural {
239 self <<= bits;
240 self
241 }
242 }
243
244 impl Shl<$t> for &Natural {
245 type Output = Natural;
246
247 /// Left-shifts a [`Natural`] (multiplies it by a power of 2), taking it by reference.
248 ///
249 /// $f(x, k) = x2^k$.
250 ///
251 /// # Worst-case complexity
252 /// $T(n, m) = O(n + m)$
253 ///
254 /// $M(n, m) = O(n + m)$
255 ///
256 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
257 /// $m$ is `bits`.
258 ///
259 /// # Examples
260 /// See [here](super::shl#shl).
261 #[inline]
262 fn shl(self, bits: $t) -> Natural {
263 shl_ref_unsigned(self, bits)
264 }
265 }
266
267 impl ShlAssign<$t> for Natural {
268 /// Left-shifts a [`Natural`] (multiplies it by a power of 2), in place.
269 ///
270 /// $x \gets x2^k$.
271 ///
272 /// # Worst-case complexity
273 /// $T(n, m) = O(n + m)$
274 ///
275 /// $M(n, m) = O(n + m)$
276 ///
277 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
278 /// $m$ is `bits`.s
279 ///
280 /// # Examples
281 /// See [here](super::shl#shl_assign).
282 #[inline]
283 fn shl_assign(&mut self, bits: $t) {
284 shl_assign(self, bits);
285 }
286 }
287 };
288}
289apply_to_unsigneds!(impl_natural_shl_unsigned);
290
291fn shl_ref_signed<'a, U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
292 x: &'a Natural,
293 bits: S,
294) -> Natural
295where
296 &'a Natural: Shl<U, Output = Natural> + Shr<U, Output = Natural>,
297{
298 if bits >= S::ZERO {
299 x << bits.unsigned_abs()
300 } else {
301 x >> bits.unsigned_abs()
302 }
303}
304
305fn shl_assign_signed<U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(x: &mut Natural, bits: S)
306where
307 Natural: ShlAssign<U> + ShrAssign<U>,
308{
309 if bits >= S::ZERO {
310 *x <<= bits.unsigned_abs();
311 } else {
312 *x >>= bits.unsigned_abs();
313 }
314}
315
316macro_rules! impl_natural_shl_signed {
317 ($t:ident) => {
318 impl Shl<$t> for Natural {
319 type Output = Natural;
320
321 /// Left-shifts a [`Natural`] (multiplies it by a power of 2 or divides it by a power of
322 /// 2 and takes the floor), taking it by value.
323 ///
324 /// $$
325 /// f(x, k) = \lfloor x2^k \rfloor.
326 /// $$
327 ///
328 /// # Worst-case complexity
329 /// $T(n, m) = O(n + m)$
330 ///
331 /// $M(n, m) = O(n + m)$
332 ///
333 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
334 /// $m$ is `max(bits, 0)`.
335 ///
336 /// # Examples
337 /// See [here](super::shl#shl).
338 #[inline]
339 fn shl(mut self, bits: $t) -> Natural {
340 self <<= bits;
341 self
342 }
343 }
344
345 impl<'a> Shl<$t> for &Natural {
346 type Output = Natural;
347
348 /// Left-shifts a [`Natural`] (multiplies it by a power of 2 or divides it by a power of
349 /// 2 and takes the floor), taking it by reference.
350 ///
351 /// $$
352 /// f(x, k) = \lfloor x2^k \rfloor.
353 /// $$
354 ///
355 /// # Worst-case complexity
356 /// $T(n, m) = O(n + m)$
357 ///
358 /// $M(n, m) = O(n + m)$
359 ///
360 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
361 /// $m$ is `max(bits, 0)`.
362 ///
363 /// # Examples
364 /// See [here](super::shl#shl).
365 #[inline]
366 fn shl(self, bits: $t) -> Natural {
367 shl_ref_signed(self, bits)
368 }
369 }
370
371 impl ShlAssign<$t> for Natural {
372 /// Left-shifts a [`Natural`] (multiplies it by a power of 2 or divides it by a power of
373 /// 2 and takes the floor), in place.
374 ///
375 /// $$
376 /// x \gets \lfloor x2^k \rfloor.
377 /// $$
378 ///
379 /// # Worst-case complexity
380 /// $T(n, m) = O(n + m)$
381 ///
382 /// $M(n, m) = O(n + m)$
383 ///
384 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
385 /// $m$ is `max(bits, 0)`.
386 ///
387 /// See [here](super::shl#shl_assign).
388 #[inline]
389 fn shl_assign(&mut self, bits: $t) {
390 shl_assign_signed(self, bits);
391 }
392 }
393 };
394}
395apply_to_signeds!(impl_natural_shl_signed);