Skip to main content

malachite_nz/natural/arithmetic/
mod_power_of_2_pow.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5//      Copyright © 2007-2009, 2012, 2015, 2016, 2018 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::arithmetic::mod_pow::{get_bits, get_window_size};
15use crate::natural::arithmetic::mod_power_of_2::limbs_vec_mod_power_of_2_in_place;
16use crate::natural::arithmetic::mod_power_of_2_square::limbs_square_low;
17use crate::natural::arithmetic::mul::mul_low::limbs_mul_low_same_length;
18use crate::natural::logic::bit_access::limbs_get_bit;
19use crate::natural::logic::significant_bits::limbs_significant_bits;
20use crate::natural::{Natural, bit_to_limb_count_ceiling};
21use crate::platform::Limb;
22use alloc::vec::Vec;
23use malachite_base::num::arithmetic::traits::{ModPowerOf2Pow, ModPowerOf2PowAssign, PowerOf2};
24use malachite_base::num::basic::integers::PrimitiveInt;
25use malachite_base::num::basic::traits::{One, Zero};
26use malachite_base::num::conversion::traits::{ConvertibleFrom, ExactFrom, WrappingFrom};
27use malachite_base::num::logic::traits::{SignificantBits, TrailingZeros};
28
29// Raise an n-limb number to a power and return the lowest n limbs of the result.
30//
31// # Worst-case complexity
32// $T(n, m) = O(mn \log n \log\log n)$
33//
34// $M(n) = O(n \log n)$
35//
36// where $T$ is time, $M$ is additional memory, $n$ is `xs.len()`, and $m$ is `es.len()`.
37//
38// This is equivalent to `mpn_powlo` from `mpn/generic/powlo.c`, GMP 6.2.1, where `rp == bp`.
39// Investigate changes from 6.1.2?
40pub_crate_test! {limbs_pow_low(xs: &mut [Limb], es: &[Limb], scratch: &mut [Limb]) {
41    let xs_len = xs.len();
42    assert_ne!(xs_len, 0);
43    let scratch = &mut scratch[..xs_len];
44    let es_len = es.len();
45    assert_ne!(es_len, 0);
46    assert_ne!(es[es_len - 1], 0);
47    assert!(es_len > 1 || es_len == 1 && es[0] > 1);
48    let mut bit_index = limbs_significant_bits(es);
49    let window_size = get_window_size(bit_index);
50    assert!(window_size < bit_index);
51    let mut powers = vec![0; xs_len << (window_size - 1)];
52    let mut powers: Vec<&mut [Limb]> = powers.chunks_mut(xs_len).collect();
53    powers[0].copy_from_slice(xs);
54    // Store x ^ 2 in scratch.
55    limbs_square_low(scratch, xs);
56    // Precompute odd powers of x and put them in `powers`.
57    for i in 1..usize::power_of_2(window_size - 1) {
58        let (powers_lo, powers_hi) = powers.split_at_mut(i);
59        limbs_mul_low_same_length(powers_hi[0], powers_lo[i - 1], scratch);
60    }
61    let mut exp_bits = get_bits(es, bit_index, window_size);
62    let trailing_zeros = TrailingZeros::trailing_zeros(Limb::exact_from(exp_bits));
63    bit_index += trailing_zeros;
64    bit_index -= window_size;
65    xs.copy_from_slice(powers[exp_bits >> trailing_zeros >> 1]);
66    while bit_index != 0 {
67        while bit_index != 0 && !limbs_get_bit(es, bit_index - 1) {
68            limbs_square_low(scratch, xs);
69            xs.copy_from_slice(scratch);
70            bit_index -= 1;
71        }
72        if bit_index == 0 {
73            break;
74        }
75        // The next bit of the exponent is 1. Now extract the largest block of bits <= window_size,
76        // and such that the least significant bit is 1.
77        exp_bits = get_bits(es, bit_index, window_size);
78        let mut this_windowsize = window_size;
79        if bit_index < window_size {
80            this_windowsize -= window_size - bit_index;
81            bit_index = 0;
82        } else {
83            bit_index -= window_size;
84        }
85        let trailing_zeros = TrailingZeros::trailing_zeros(Limb::exact_from(exp_bits));
86        this_windowsize -= trailing_zeros;
87        bit_index += trailing_zeros;
88        while this_windowsize > 1 {
89            limbs_square_low(scratch, xs);
90            limbs_square_low(xs, scratch);
91            this_windowsize -= 2;
92        }
93        if this_windowsize == 1 {
94            limbs_square_low(scratch, xs);
95        } else {
96            scratch.copy_from_slice(xs);
97        }
98        limbs_mul_low_same_length(xs, scratch, powers[exp_bits >> trailing_zeros >> 1]);
99    }
100}}
101
102// Interpreting a `Vec<Limb>` and a `&[Limb]` as the limbs (in ascending order) of two `Natural`s,
103// writes the limbs of the first `Natural` raised to the second, mod $2^k$, to the input `Vec`.
104// Assumes the input is already reduced mod $2^k$. Neither input may be empty or have trailing
105// zeros, and the exponent must be greater than 1.
106//
107// # Worst-case complexity
108// $T(n, m) = O(mn \log n \log\log n)$
109//
110// $M(n) = O(n \log n)$
111//
112// where $T$ is time, $M$ is additional memory, $n$ is `xs.len()`, and $m$ is `es.len()`.
113//
114// # Panics
115// Panics if the exponent has trailing zeros or is 1.
116pub_test! {limbs_mod_power_of_2_pow(xs: &mut Vec<Limb>, es: &[Limb], pow: u64) {
117    let out_len = bit_to_limb_count_ceiling(pow);
118    xs.resize(out_len, 0);
119    let mut scratch = vec![0; out_len];
120    limbs_pow_low(xs, es, &mut scratch);
121    limbs_vec_mod_power_of_2_in_place(xs, pow);
122}}
123
124impl ModPowerOf2Pow<Self> for Natural {
125    type Output = Self;
126
127    /// Raises a [`Natural`] to a [`Natural`] power modulo $2^k$. The base must be already reduced
128    /// modulo $2^k$. Both [`Natural`]s are taken by value.
129    ///
130    /// $f(x, n, k) = y$, where $x, y < 2^k$ and $x^n \equiv y \mod 2^k$.
131    ///
132    /// # Worst-case complexity
133    /// $T(n, m) = O(mn \log n \log\log n)$
134    ///
135    /// $M(n) = O(n \log n)$
136    ///
137    /// where $T$ is time, $M$ is additional memory, $n$ is `pow`, and $m$ is
138    /// `exp.significant_bits()`.
139    ///
140    /// # Panics
141    /// Panics if `self` is greater than or equal to $2^k$.
142    ///
143    /// # Examples
144    /// ```
145    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Pow;
146    /// use malachite_nz::natural::Natural;
147    ///
148    /// assert_eq!(
149    ///     Natural::from(3u32).mod_power_of_2_pow(Natural::from(10u32), 8),
150    ///     169
151    /// );
152    /// assert_eq!(
153    ///     Natural::from(11u32).mod_power_of_2_pow(Natural::from(1000u32), 30),
154    ///     289109473
155    /// );
156    /// ```
157    #[inline]
158    fn mod_power_of_2_pow(mut self, exp: Self, pow: u64) -> Self {
159        self.mod_power_of_2_pow_assign(exp, pow);
160        self
161    }
162}
163
164impl ModPowerOf2Pow<&Self> for Natural {
165    type Output = Self;
166
167    /// Raises a [`Natural`] to a [`Natural`] power modulo $2^k$. The base must be already reduced
168    /// modulo $2^k$. The first [`Natural`] is taken by value and the second by reference.
169    ///
170    /// $f(x, n, k) = y$, where $x, y < 2^k$ and $x^n \equiv y \mod 2^k$.
171    ///
172    /// # Worst-case complexity
173    /// $T(n, m) = O(mn \log n \log\log n)$
174    ///
175    /// $M(n) = O(n \log n)$
176    ///
177    /// where $T$ is time, $M$ is additional memory, $n$ is `pow`, and $m$ is
178    /// `exp.significant_bits()`.
179    ///
180    /// # Panics
181    /// Panics if `self` is greater than or equal to $2^k$.
182    ///
183    /// # Examples
184    /// ```
185    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Pow;
186    /// use malachite_nz::natural::Natural;
187    ///
188    /// assert_eq!(
189    ///     Natural::from(3u32).mod_power_of_2_pow(&Natural::from(10u32), 8),
190    ///     169
191    /// );
192    /// assert_eq!(
193    ///     Natural::from(11u32).mod_power_of_2_pow(&Natural::from(1000u32), 30),
194    ///     289109473
195    /// );
196    /// ```
197    #[inline]
198    fn mod_power_of_2_pow(mut self, exp: &Self, pow: u64) -> Self {
199        self.mod_power_of_2_pow_assign(exp, pow);
200        self
201    }
202}
203
204impl ModPowerOf2Pow<Natural> for &Natural {
205    type Output = Natural;
206
207    /// Raises a [`Natural`] to a [`Natural`] power modulo $2^k$. The base must be already reduced
208    /// modulo $2^k$. The first [`Natural`] is taken by reference and the second by value.
209    ///
210    /// $f(x, n, k) = y$, where $x, y < 2^k$ and $x^n \equiv y \mod 2^k$.
211    ///
212    /// # Worst-case complexity
213    /// $T(n, m) = O(mn \log n \log\log n)$
214    ///
215    /// $M(n) = O(n \log n)$
216    ///
217    /// where $T$ is time, $M$ is additional memory, $n$ is `pow`, and $m$ is
218    /// `exp.significant_bits()`.
219    ///
220    /// # Panics
221    /// Panics if `self` is greater than or equal to $2^k$.
222    ///
223    /// # Examples
224    /// ```
225    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Pow;
226    /// use malachite_nz::natural::Natural;
227    ///
228    /// assert_eq!(
229    ///     (&Natural::from(3u32)).mod_power_of_2_pow(Natural::from(10u32), 8),
230    ///     169
231    /// );
232    /// assert_eq!(
233    ///     (&Natural::from(11u32)).mod_power_of_2_pow(Natural::from(1000u32), 30),
234    ///     289109473
235    /// );
236    /// ```
237    #[inline]
238    fn mod_power_of_2_pow(self, exp: Natural, pow: u64) -> Natural {
239        self.mod_power_of_2_pow(&exp, pow)
240    }
241}
242
243impl ModPowerOf2Pow<&Natural> for &Natural {
244    type Output = Natural;
245
246    /// Raises a [`Natural`] to a [`Natural`] power modulo $2^k$. The base must be already reduced
247    /// modulo $2^k$. Both [`Natural`]s are taken by reference.
248    ///
249    /// # Worst-case complexity
250    /// $T(n, m) = O(mn \log n \log\log n)$
251    ///
252    /// $M(n) = O(n \log n)$
253    ///
254    /// where $T$ is time, $M$ is additional memory, $n$ is `pow`, and $m$ is
255    /// `exp.significant_bits()`.
256    ///
257    /// # Panics
258    /// Panics if `self` is greater than or equal to $2^k$.
259    ///
260    /// # Examples
261    /// ```
262    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Pow;
263    /// use malachite_nz::natural::Natural;
264    ///
265    /// assert_eq!(
266    ///     (&Natural::from(3u32)).mod_power_of_2_pow(&Natural::from(10u32), 8),
267    ///     169
268    /// );
269    /// assert_eq!(
270    ///     (&Natural::from(11u32)).mod_power_of_2_pow(&Natural::from(1000u32), 30),
271    ///     289109473
272    /// );
273    /// ```
274    #[inline]
275    fn mod_power_of_2_pow(self, exp: &Natural, pow: u64) -> Natural {
276        assert!(
277            self.significant_bits() <= pow,
278            "self must be reduced mod 2^pow, but {self} >= 2^{pow}"
279        );
280        match (self, exp) {
281            _ if pow == 0 => Natural::ZERO,
282            (_, &Natural::ZERO) => Natural::ONE,
283            (&Natural::ZERO | &Natural::ONE, _) | (_, &Natural::ONE) => self.clone(),
284            (Natural(Small(x)), Natural(Small(e)))
285                if pow <= Limb::WIDTH && u64::convertible_from(*e) =>
286            {
287                Natural(Small(x.mod_power_of_2_pow(u64::wrapping_from(*e), pow)))
288            }
289            (_, Natural(Small(e))) => {
290                let mut xs = self.to_limbs_asc();
291                limbs_mod_power_of_2_pow(&mut xs, &[*e], pow);
292                Natural::from_owned_limbs_asc(xs)
293            }
294            (_, Natural(Large(es))) => {
295                let mut xs = self.to_limbs_asc();
296                limbs_mod_power_of_2_pow(&mut xs, es, pow);
297                Natural::from_owned_limbs_asc(xs)
298            }
299        }
300    }
301}
302
303impl ModPowerOf2PowAssign<Self> for Natural {
304    /// Raises a [`Natural`] to a [`Natural`] power modulo $2^k$, in place. The base must be already
305    /// reduced modulo $2^k$. The [`Natural`] on the right-hand side is taken by value.
306    ///
307    /// $x \gets y$, where $x, y < 2^k$ and $x^n \equiv y \mod 2^k$.
308    ///
309    /// # Worst-case complexity
310    /// $T(n, m) = O(mn \log n \log\log n)$
311    ///
312    /// $M(n) = O(n \log n)$
313    ///
314    /// where $T$ is time, $M$ is additional memory, $n$ is `pow`, and $m$ is
315    /// `exp.significant_bits()`.
316    ///
317    /// # Panics
318    /// Panics if `self` is greater than or equal to $2^k$.
319    ///
320    /// # Examples
321    /// ```
322    /// use malachite_base::num::arithmetic::traits::ModPowerOf2PowAssign;
323    /// use malachite_nz::natural::Natural;
324    ///
325    /// let mut x = Natural::from(3u32);
326    /// x.mod_power_of_2_pow_assign(Natural::from(10u32), 8);
327    /// assert_eq!(x, 169);
328    ///
329    /// let mut x = Natural::from(11u32);
330    /// x.mod_power_of_2_pow_assign(Natural::from(1000u32), 30);
331    /// assert_eq!(x, 289109473);
332    /// ```
333    #[inline]
334    fn mod_power_of_2_pow_assign(&mut self, exp: Self, pow: u64) {
335        self.mod_power_of_2_pow_assign(&exp, pow);
336    }
337}
338
339impl ModPowerOf2PowAssign<&Self> for Natural {
340    /// Raises a [`Natural`] to a [`Natural`] power modulo $2^k$, in place. The base must be already
341    /// reduced modulo $2^k$. The [`Natural`] on the right-hand side is taken by reference.
342    ///
343    /// $x \gets y$, where $x, y < 2^k$ and $x^n \equiv y \mod 2^k$.
344    ///
345    /// # Worst-case complexity
346    /// $T(n, m) = O(mn \log n \log\log n)$
347    ///
348    /// $M(n) = O(n \log n)$
349    ///
350    /// where $T$ is time, $M$ is additional memory, $n$ is `pow`, and $m$ is
351    /// `exp.significant_bits()`.
352    ///
353    /// # Panics
354    /// Panics if `self` is greater than or equal to $2^k$.
355    ///
356    /// # Examples
357    /// ```
358    /// use malachite_base::num::arithmetic::traits::ModPowerOf2PowAssign;
359    /// use malachite_nz::natural::Natural;
360    ///
361    /// let mut x = Natural::from(3u32);
362    /// x.mod_power_of_2_pow_assign(&Natural::from(10u32), 8);
363    /// assert_eq!(x, 169);
364    ///
365    /// let mut x = Natural::from(11u32);
366    /// x.mod_power_of_2_pow_assign(&Natural::from(1000u32), 30);
367    /// assert_eq!(x, 289109473);
368    /// ```
369    fn mod_power_of_2_pow_assign(&mut self, exp: &Self, pow: u64) {
370        assert!(
371            self.significant_bits() <= pow,
372            "self must be reduced mod 2^pow, but {self} >= 2^{pow}"
373        );
374        match (&mut *self, exp) {
375            _ if pow == 0 => *self = Self::ZERO,
376            (_, &Self::ZERO) => *self = Self::ONE,
377            (&mut (Self::ZERO | Self::ONE), _) | (_, &Self::ONE) => {}
378            (Self(Small(x)), Self(Small(e))) if pow <= Limb::WIDTH && u64::convertible_from(*e) => {
379                x.mod_power_of_2_pow_assign(u64::wrapping_from(*e), pow);
380            }
381            (_, Self(Small(e))) => {
382                let xs = self.promote_in_place();
383                limbs_mod_power_of_2_pow(xs, &[*e], pow);
384                self.trim();
385            }
386            (_, Self(Large(es))) => {
387                let xs = self.promote_in_place();
388                limbs_mod_power_of_2_pow(xs, es, pow);
389                self.trim();
390            }
391        }
392    }
393}