Skip to main content

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