Skip to main content

malachite_nz/natural/arithmetic/
mod_power_of_2_shl.rs

1// Copyright © 2026 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::natural::Natural;
10use core::ops::{Shr, ShrAssign};
11use malachite_base::num::arithmetic::traits::{
12    ModPowerOf2, ModPowerOf2Assign, ModPowerOf2Shl, ModPowerOf2ShlAssign, UnsignedAbs,
13};
14use malachite_base::num::basic::signeds::PrimitiveSigned;
15use malachite_base::num::basic::traits::Zero;
16use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
17use malachite_base::num::conversion::traits::ExactFrom;
18use malachite_base::num::logic::traits::SignificantBits;
19
20fn mod_power_of_2_shl_unsigned_nz<T: PrimitiveUnsigned>(x: &Natural, bits: T, pow: u64) -> Natural
21where
22    u64: ExactFrom<T>,
23{
24    assert!(
25        x.significant_bits() <= pow,
26        "x must be reduced mod 2^pow, but {x} >= 2^{pow}"
27    );
28    let bits = u64::exact_from(bits);
29    if bits >= pow {
30        Natural::ZERO
31    } else {
32        x.mod_power_of_2(pow - bits) << bits
33    }
34}
35
36fn mod_power_of_2_shl_assign_unsigned_nz<T: PrimitiveUnsigned>(x: &mut Natural, bits: T, pow: u64)
37where
38    u64: ExactFrom<T>,
39{
40    assert!(
41        x.significant_bits() <= pow,
42        "x must be reduced mod 2^pow, but {x} >= 2^{pow}"
43    );
44    let bits = u64::exact_from(bits);
45    if bits >= pow {
46        *x = Natural::ZERO;
47    } else {
48        x.mod_power_of_2_assign(pow - bits);
49        *x <<= bits;
50    }
51}
52
53macro_rules! impl_mod_power_of_2_shl_unsigned {
54    ($t:ident) => {
55        impl ModPowerOf2Shl<$t> for Natural {
56            type Output = Natural;
57
58            /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo $2^k$. The
59            /// [`Natural`] must be already reduced modulo $2^k$. The [`Natural`] is taken by value.
60            ///
61            /// $f(x, n, k) = y$, where $x, y < 2^k$ and $2^nx \equiv y \mod 2^k$.
62            ///
63            /// # Worst-case complexity
64            /// $T(n) = O(n)$
65            ///
66            /// $M(n) = O(n)$
67            ///
68            /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
69            ///
70            /// # Panics
71            /// Panics if `self` is greater than or equal to $2^k$.
72            ///
73            /// # Examples
74            /// See [here](super::mod_power_of_2_shl#mod_power_of_2_shl).
75            #[inline]
76            fn mod_power_of_2_shl(mut self, bits: $t, pow: u64) -> Natural {
77                self.mod_power_of_2_shl_assign(bits, pow);
78                self
79            }
80        }
81
82        impl ModPowerOf2Shl<$t> for &Natural {
83            type Output = Natural;
84
85            /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo $2^k$. The
86            /// [`Natural`] must be already reduced modulo $2^k$. The [`Natural`] is taken by
87            /// reference.
88            ///
89            /// $f(x, n, k) = y$, where $x, y < 2^k$ and $2^nx \equiv y \mod 2^k$.
90            ///
91            /// # Worst-case complexity
92            /// $T(n) = O(n)$
93            ///
94            /// $M(n) = O(n)$
95            ///
96            /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
97            ///
98            /// # Panics
99            /// Panics if `self` is greater than or equal to $2^k$.
100            ///
101            /// # Examples
102            /// See [here](super::mod_power_of_2_shl#mod_power_of_2_shl).
103            #[inline]
104            fn mod_power_of_2_shl(self, bits: $t, pow: u64) -> Natural {
105                mod_power_of_2_shl_unsigned_nz(self, bits, pow)
106            }
107        }
108
109        impl ModPowerOf2ShlAssign<$t> for Natural {
110            /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo $2^k$, in place.
111            /// The [`Natural`] must be already reduced modulo $2^k$.
112            ///
113            /// $x \gets y$, where $x, y < 2^k$ and $2^nx \equiv y \mod 2^k$.
114            ///
115            /// # Worst-case complexity
116            /// $T(n) = O(n)$
117            ///
118            /// $M(n) = O(n)$
119            ///
120            /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
121            ///
122            /// # Panics
123            /// Panics if `self` is greater than or equal to $2^k$.
124            ///
125            /// # Examples
126            /// See [here](super::mod_power_of_2_shl#mod_power_of_2_shl_assign).
127            #[inline]
128            fn mod_power_of_2_shl_assign(&mut self, bits: $t, pow: u64) {
129                mod_power_of_2_shl_assign_unsigned_nz(self, bits, pow);
130            }
131        }
132    };
133}
134apply_to_unsigneds!(impl_mod_power_of_2_shl_unsigned);
135
136fn mod_power_of_2_shl_signed_nz<'a, U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
137    x: &'a Natural,
138    bits: S,
139    pow: u64,
140) -> Natural
141where
142    &'a Natural: ModPowerOf2Shl<U, Output = Natural> + Shr<U, Output = Natural>,
143{
144    assert!(
145        x.significant_bits() <= pow,
146        "x must be reduced mod 2^pow, but {x} >= 2^{pow}"
147    );
148    if bits >= S::ZERO {
149        x.mod_power_of_2_shl(bits.unsigned_abs(), pow)
150    } else {
151        x >> bits.unsigned_abs()
152    }
153}
154
155fn mod_power_of_2_shl_assign_signed_nz<U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
156    x: &mut Natural,
157    bits: S,
158    pow: u64,
159) where
160    Natural: ModPowerOf2ShlAssign<U> + ShrAssign<U>,
161{
162    assert!(
163        x.significant_bits() <= pow,
164        "x must be reduced mod 2^pow, but {x} >= 2^{pow}"
165    );
166    if bits >= S::ZERO {
167        x.mod_power_of_2_shl_assign(bits.unsigned_abs(), pow);
168    } else {
169        *x >>= bits.unsigned_abs();
170    }
171}
172
173macro_rules! impl_mod_power_of_2_shl_signed {
174    ($t:ident) => {
175        impl ModPowerOf2Shl<$t> for Natural {
176            type Output = Natural;
177
178            /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo $2^k$. The
179            /// [`Natural`] must be already reduced modulo $2^k$. The [`Natural`] is taken by value.
180            ///
181            /// $f(x, n, k) = y$, where $x, y < 2^k$ and $\lfloor 2^nx \rfloor \equiv y \mod 2^k$.
182            ///
183            /// # Worst-case complexity
184            /// $T(n) = O(n)$
185            ///
186            /// $M(n) = O(n)$
187            ///
188            /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
189            ///
190            /// # Panics
191            /// Panics if `self` is greater than or equal to $2^k$.
192            ///
193            /// # Examples
194            /// See [here](super::mod_power_of_2_shl#mod_power_of_2_shl).
195            #[inline]
196            fn mod_power_of_2_shl(mut self, bits: $t, pow: u64) -> Natural {
197                self.mod_power_of_2_shl_assign(bits, pow);
198                self
199            }
200        }
201
202        impl ModPowerOf2Shl<$t> for &Natural {
203            type Output = Natural;
204
205            /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo $2^k$. The
206            /// [`Natural`] must be already reduced modulo $2^k$. The [`Natural`] is taken by
207            /// reference.
208            ///
209            /// $f(x, n, k) = y$, where $x, y < 2^k$ and $\lfloor 2^nx \rfloor \equiv y \mod 2^k$.
210            ///
211            /// # Worst-case complexity
212            /// $T(n) = O(n)$
213            ///
214            /// $M(n) = O(n)$
215            ///
216            /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
217            ///
218            /// # Panics
219            /// Panics if `self` is greater than or equal to $2^k$.
220            ///
221            /// # Examples
222            /// See [here](super::mod_power_of_2_shl#mod_power_of_2_shl).
223            #[inline]
224            fn mod_power_of_2_shl(self, bits: $t, pow: u64) -> Natural {
225                mod_power_of_2_shl_signed_nz(self, bits, pow)
226            }
227        }
228
229        impl ModPowerOf2ShlAssign<$t> for Natural {
230            /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo $2^k$, in place.
231            /// The [`Natural`] must be already reduced modulo $2^k$.
232            ///
233            /// $x \gets y$, where $x, y < 2^k$ and $\lfloor 2^nx \rfloor \equiv y \mod 2^k$.
234            ///
235            /// # Worst-case complexity
236            /// $T(n) = O(n)$
237            ///
238            /// $M(n) = O(n)$
239            ///
240            /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
241            ///
242            /// # Panics
243            /// Panics if `self` is greater than or equal to $2^k$.
244            ///
245            /// # Examples
246            /// See [here](super::mod_power_of_2_shl#mod_power_of_2_shl_assign).
247            #[inline]
248            fn mod_power_of_2_shl_assign(&mut self, bits: $t, pow: u64) {
249                mod_power_of_2_shl_assign_signed_nz(self, bits, pow)
250            }
251        }
252    };
253}
254apply_to_signeds!(impl_mod_power_of_2_shl_signed);