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