Skip to main content

malachite_nz/natural/arithmetic/
pow.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5//      Copyright © 1991, 1993-1997, 1999-2016, 2020 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::mul::limb::limbs_slice_mul_limb_in_place;
15use crate::natural::arithmetic::mul::{
16    limbs_mul_greater_to_out, limbs_mul_greater_to_out_scratch_len,
17};
18use crate::natural::arithmetic::shl::limbs_slice_shl_in_place;
19use crate::natural::arithmetic::shr::limbs_shr_to_out;
20use crate::natural::arithmetic::square::{limbs_square_to_out, limbs_square_to_out_scratch_len};
21#[cfg(feature = "test_build")]
22use crate::natural::bit_to_limb_count_ceiling;
23#[cfg(feature = "test_build")]
24use crate::natural::logic::significant_bits::limbs_significant_bits;
25use crate::natural::{Natural, bit_to_limb_count_floor, limb_to_bit_count};
26#[cfg(feature = "test_build")]
27use crate::platform::DoubleLimb;
28use crate::platform::Limb;
29use alloc::vec::Vec;
30use core::mem::swap;
31use malachite_base::num::arithmetic::traits::{
32    EqModPowerOf2, Parity, Pow, PowAssign, Square, SquareAssign,
33};
34#[cfg(feature = "test_build")]
35use malachite_base::num::arithmetic::traits::{IsPowerOf2, PowerOf2};
36use malachite_base::num::basic::integers::PrimitiveInt;
37use malachite_base::num::basic::traits::{One, Zero};
38#[cfg(feature = "test_build")]
39use malachite_base::num::conversion::traits::SplitInHalf;
40use malachite_base::num::conversion::traits::{ExactFrom, WrappingFrom};
41#[cfg(feature = "test_build")]
42use malachite_base::num::logic::traits::BitAccess;
43use malachite_base::num::logic::traits::{
44    BitIterable, CountOnes, LeadingZeros, SignificantBits, TrailingZeros,
45};
46use malachite_base::slices::slice_leading_zeros;
47
48/// This is equivalent to `GMP_NUMB_HALFMAX` from `mpz/n_pow_ui.c`, GMP 6.2.1.
49const HALF_MAX: Limb = (1 << (Limb::WIDTH >> 1)) - 1;
50
51// # Worst-case complexity
52// $T(n, m) = O(nm \log (nm) \log\log (nm))$
53//
54// $M(n, m) = O(nm \log (nm))$
55//
56// where $T$ is time, $M$ is additional memory, $n$ is `xs.len()`, and $m$ is `exp`.
57pub_crate_test! {limbs_pow(xs: &[Limb], exp: u64) -> Vec<Limb> {
58    let mut out = Vec::new();
59    let out_len = limbs_pow_to_out(&mut out, xs, exp);
60    out.truncate(out_len);
61    out
62}}
63
64// # Worst-case complexity
65// $T(n) = O(n \log n \log\log n)$
66//
67// $M(n) = O(n \log n)$
68//
69// where $T$ is time, $M$ is additional memory, and $n$ is `exp`.
70fn len_1_helper(x_0: &mut Limb, out_0: &mut Limb, trailing_zero_bits_out: &mut u64, exp: &mut u64) {
71    // Power up as far as possible within `x_0`. We start here with `exp` != 0, but if `exp` is
72    // small then we might reach `exp` == 0 and the whole `x` ^ `exp` in `out_0`.
73    while *x_0 <= HALF_MAX {
74        assert_ne!(*exp, 0);
75        if exp.odd() {
76            *out_0 *= *x_0;
77        }
78        *exp >>= 1;
79        if *exp == 0 {
80            break;
81        }
82        x_0.square_assign();
83    }
84    // Combine leftover `trailing_zero_bits_out` into `out_0` to be handled by the final
85    // `limbs_slice_mul_limb_in_place` rather than a separate `limbs_slice_shl_in_place`.
86    // - `out_0` mustn't be 1 (since then there's no final mul)
87    // - `out_0` mustn't overflow
88    if *trailing_zero_bits_out != 0
89        && *out_0 != 1
90        && *out_0 >> (Limb::WIDTH - *trailing_zero_bits_out) == 0
91    {
92        *out_0 <<= *trailing_zero_bits_out;
93        *trailing_zero_bits_out = 0;
94    }
95}
96
97// # Worst-case complexity
98// $T(n, m) = O(nm \log (nm) \log\log (nm))$
99//
100// $M(n, m) = O(nm \log (nm))$
101//
102// where $T$ is time, $M$ is additional memory, $n$ is `xs.len()`, and $m$ is `exp`.
103//
104// This is equivalent to `mpz_n_pow_ui` from `mpz/n_pow_ui.c`, GMP 6.2.1, where `e > 1` and
105// `bp.len() != 0`. Returns `rsize`.
106fn limbs_pow_to_out(out: &mut Vec<Limb>, xs: &[Limb], mut exp: u64) -> usize {
107    assert!(exp > 1);
108    let leading_zeros_in = slice_leading_zeros(xs);
109    let mut leading_zeros_out = leading_zeros_in * usize::exact_from(exp);
110    let mut xs = &xs[leading_zeros_in..];
111    let mut x = xs[0];
112    // Strip low zero bits from b.
113    let trailing_zero_bits_in = TrailingZeros::trailing_zeros(x);
114    x >>= trailing_zero_bits_in;
115    let mut trailing_zero_bits_out = exp * trailing_zero_bits_in;
116    leading_zeros_out += bit_to_limb_count_floor(trailing_zero_bits_out);
117    trailing_zero_bits_out &= Limb::WIDTH_MASK;
118    let mut out_0 = 1;
119    let mut scratch;
120    let mut x_0_x_1 = [0; 2];
121    match xs.len() {
122        1 => len_1_helper(&mut x, &mut out_0, &mut trailing_zero_bits_out, &mut exp),
123        2 => {
124            let mut x_1 = xs[1];
125            if trailing_zero_bits_in != 0 {
126                x |= x_1 << (Limb::WIDTH - trailing_zero_bits_in);
127            }
128            x_1 >>= trailing_zero_bits_in;
129            if x_1 == 0 {
130                // Two limbs became one after rshift.
131                xs = &xs[..1];
132                len_1_helper(&mut x, &mut out_0, &mut trailing_zero_bits_out, &mut exp);
133            } else {
134                x_0_x_1[0] = x;
135                x_0_x_1[1] = x_1;
136                xs = &x_0_x_1;
137                x = x_1;
138            }
139        }
140        len => {
141            if trailing_zero_bits_in != 0 {
142                scratch = vec![0; len];
143                limbs_shr_to_out(&mut scratch, xs, trailing_zero_bits_in);
144                if *scratch.last().unwrap() == 0 {
145                    scratch.pop();
146                }
147                xs = &scratch;
148            }
149            x = *xs.last().unwrap();
150        }
151    }
152    let len = xs.len();
153    // At this point `x` is the most significant limb of the base to use.
154    //
155    // Each factor of `xs` takes (len * 2 ^ `Limb::WIDTH` - `bits`) bits and there's `exp` of them;
156    // +1 limb to round up the division; +1 for multiplies all using an extra limb over the true
157    // size; +2 for `out_0` at the end; +1 for `limbs_slice_shl_in_place` at the end.
158    //
159    // The size calculation here is reasonably accurate. The base is at least half a limb, so in 32
160    // bits the worst case is 2 ^ 16 + 1 treated as 17 bits when it will power up as just over 16,
161    // an overestimate of 17/16 = 6.25%. For a 64-bit limb it's half that.
162    assert_ne!(x, 0);
163    let mut out_alloc =
164        bit_to_limb_count_floor((limb_to_bit_count(len) - LeadingZeros::leading_zeros(x)) * exp)
165            + 5;
166    out.resize(out_alloc + leading_zeros_out, 0);
167    // Low zero limbs resulting from powers of 2.
168    let out_original = out;
169    let mut out = &mut out_original[leading_zeros_out..];
170    let mut out_len;
171    let mut scratch;
172    if exp == 0 {
173        out[0] = out_0;
174        out_len = 1;
175        assert_ne!(out[0], 0);
176    } else {
177        // In the `limbs_slice_mul_limb_in_place` loop or in the `limbs_mul_greater_to_out` loop
178        // when the low bit of `exp` is zero, `scratch` only has to hold the second last power step,
179        // which is half the size of the final result. There's no need to round up the divide by 2,
180        // since `out_alloc` includes a +2 for `out_0` which is not needed by `scratch`. In the
181        // `limbs_mul_greater_to_out` loop when the low bit of `exp` is 1, `scratch` must hold
182        // nearly the full result, so just size it the same as `out`.
183        let mut scratch_len = out_alloc;
184        if len == 1 || exp.even() {
185            scratch_len >>= 1;
186        }
187        scratch = vec![0; scratch_len];
188        let mut scratch: &mut [Limb] = &mut scratch;
189        let bits = LeadingZeros::leading_zeros(exp);
190        if len == 1 {
191            // Arrange the final result ends up in `out`, not in `scratch`
192            if bits.even() {
193                swap(&mut out, &mut scratch);
194                swap(&mut out_alloc, &mut scratch_len);
195            }
196            out[0] = x;
197            out_len = 1;
198            for bit in exp.bits().rev().skip(1) {
199                assert!(out_len << 1 <= scratch_len);
200                let mut square_scratch = vec![0; limbs_square_to_out_scratch_len(out_len)];
201                limbs_square_to_out(scratch, &out[..out_len], &mut square_scratch);
202                out_len <<= 1;
203                if scratch[out_len - 1] == 0 {
204                    out_len -= 1;
205                }
206                swap(&mut out, &mut scratch);
207                swap(&mut out_alloc, &mut scratch_len);
208                if bit {
209                    assert!(out_len < out_alloc);
210                    let carry = limbs_slice_mul_limb_in_place(&mut out[..out_len], x);
211                    out[out_len] = carry;
212                    if carry != 0 {
213                        out_len += 1;
214                    }
215                }
216            }
217            if out_0 != 1 {
218                assert!(out_len < out_alloc);
219                let carry = limbs_slice_mul_limb_in_place(&mut out[..out_len], out_0);
220                out[out_len] = carry;
221                if carry != 0 {
222                    out_len += 1;
223                }
224            }
225        } else {
226            // Arrange the final result ends up in `out`, not in `scratch`
227            if !CountOnes::count_ones(exp).eq_mod_power_of_2(bits, 1) {
228                swap(&mut out, &mut scratch);
229                swap(&mut out_alloc, &mut scratch_len);
230            }
231            out[..len].copy_from_slice(xs);
232            out_len = len;
233            for bit in exp.bits().rev().skip(1) {
234                assert!(out_len << 1 <= scratch_len);
235                let mut square_scratch = vec![0; limbs_square_to_out_scratch_len(out_len)];
236                limbs_square_to_out(scratch, &out[..out_len], &mut square_scratch);
237                out_len <<= 1;
238                if scratch[out_len - 1] == 0 {
239                    out_len -= 1;
240                }
241                swap(&mut out, &mut scratch);
242                swap(&mut out_alloc, &mut scratch_len);
243                if bit {
244                    assert!(out_len + len <= scratch_len);
245                    let mut mul_scratch =
246                        vec![0; limbs_mul_greater_to_out_scratch_len(out_len, len)];
247                    let carry =
248                        limbs_mul_greater_to_out(scratch, &out[..out_len], xs, &mut mul_scratch);
249                    out_len += len;
250                    if carry == 0 {
251                        out_len -= 1;
252                    }
253                    swap(&mut out, &mut scratch);
254                    swap(&mut out_alloc, &mut scratch_len);
255                }
256            }
257        }
258    }
259    // Apply any partial limb factors of 2.
260    if trailing_zero_bits_out != 0 {
261        assert!(out_len < out_alloc);
262        let carry = limbs_slice_shl_in_place(&mut out[..out_len], trailing_zero_bits_out);
263        out[out_len] = carry;
264        if carry != 0 {
265            out_len += 1;
266        }
267    }
268    assert_eq!(
269        out as *const [Limb],
270        &out_original[leading_zeros_out..] as *const [Limb]
271    );
272    out_len + leading_zeros_out
273}
274
275// # Worst-case complexity
276// Constant time and additional memory.
277#[cfg(feature = "test_build")]
278fn exp_predecessor(exp: u64) -> u64 {
279    if exp.even() { exp >> 1 } else { exp - 1 }
280}
281
282// # Worst-case complexity
283// Constant time and additional memory.
284#[cfg(feature = "test_build")]
285fn estimated_limb_len_helper(x: Limb, exp: u64) -> usize {
286    bit_to_limb_count_ceiling(x.significant_bits() * exp)
287}
288
289// # Worst-case complexity
290// Constant time and additional memory.
291//
292// Never an underestimate.
293#[cfg(feature = "test_build")]
294fn limb_pow_alt_estimated_out_len(x: Limb, exp: u64) -> usize {
295    if exp.even() {
296        estimated_limb_len_helper(x, exp >> 1) << 1
297    } else {
298        estimated_limb_len_helper(x, exp - 1) + 1
299    }
300}
301
302// # Worst-case complexity
303// Constant time and additional memory.
304//
305// Never an underestimate.
306#[cfg(feature = "test_build")]
307#[inline]
308fn limb_pow_alt_estimated_scratch_len(x: Limb, exp: u64) -> usize {
309    limb_pow_alt_estimated_out_len(x, exp_predecessor(exp))
310}
311
312// TODO figure out how to find scratch len using mp_bases. x > 1.
313//
314// # Worst-case complexity
315// $T(n) = O(n \log n \log\log n)$
316//
317// $M(n) = O(n \log n)$
318//
319// where $T$ is time, $M$ is additional memory, and $n$ is `exp`.
320//
321// This is equivalent to `mpn_pow_1` from `mpn/generic/pow_1.c`, GMP 6.2.1, where `exp > 1` and `bn
322// == 1`.
323#[cfg(feature = "test_build")]
324fn limb_pow_to_out_alt<'a>(
325    mut out: &'a mut [Limb],
326    x: Limb,
327    exp: u64,
328    mut scratch: &'a mut [Limb],
329) -> usize {
330    assert!(x > 1);
331    assert!(exp > 1);
332    // Count number of bits in exp, and compute where to put initial square in order to magically
333    // get results in the entry out.
334    let bits = exp.significant_bits();
335    if bits.odd() {
336        swap(&mut out, &mut scratch);
337    }
338    (out[1], out[0]) = DoubleLimb::from(x).square().split_in_half();
339    let mut out_len = if out[1] == 0 { 1 } else { 2 };
340    for i in (0..bits - 1).rev() {
341        if exp.get_bit(i) {
342            let (out_last, out_init) = out[..=out_len].split_last_mut().unwrap();
343            *out_last = limbs_slice_mul_limb_in_place(out_init, x);
344            if *out_last != 0 {
345                out_len += 1;
346            }
347        }
348        if i == 0 {
349            break;
350        }
351        let mut square_scratch = vec![0; limbs_square_to_out_scratch_len(out_len)];
352        limbs_square_to_out(scratch, &out[..out_len], &mut square_scratch);
353        out_len <<= 1;
354        if scratch[out_len - 1] == 0 {
355            out_len -= 1;
356        }
357        swap(&mut out, &mut scratch);
358    }
359    out_len
360}
361
362// # Worst-case complexity
363// $T(n) = O(n \log n \log\log n)$
364//
365// $M(n) = O(n \log n)$
366//
367// where $T$ is time, $M$ is additional memory, and $n$ is `exp`.
368#[cfg(feature = "test_build")]
369fn limb_pow_alt(x: Limb, exp: u64) -> Vec<Limb> {
370    let mut out = vec![0; limb_pow_alt_estimated_out_len(x, exp)];
371    let mut scratch = vec![0; limb_pow_alt_estimated_scratch_len(x, exp)];
372    let out_len = limb_pow_to_out_alt(&mut out, x, exp, &mut scratch);
373    assert!(out_len <= out.len());
374    out.truncate(out_len);
375    out
376}
377
378// # Worst-case complexity
379// Constant time and additional memory.
380#[cfg(feature = "test_build")]
381fn estimated_limbs_len_helper(xs: &[Limb], exp: u64) -> usize {
382    bit_to_limb_count_ceiling(limbs_significant_bits(xs) * exp)
383}
384
385// # Worst-case complexity
386// Constant time and additional memory.
387//
388// Never an underestimate.
389#[cfg(feature = "test_build")]
390fn limbs_pow_alt_estimated_out_len(xs: &[Limb], exp: u64) -> usize {
391    if exp.even() {
392        estimated_limbs_len_helper(xs, exp >> 1) << 1
393    } else {
394        estimated_limbs_len_helper(xs, exp - 1) + xs.len()
395    }
396}
397
398// # Worst-case complexity
399// Constant time and additional memory.
400//
401// Never an underestimate.
402#[cfg(feature = "test_build")]
403#[inline]
404fn limbs_pow_alt_estimated_scratch_len(xs: &[Limb], exp: u64) -> usize {
405    limbs_pow_alt_estimated_out_len(xs, exp_predecessor(exp))
406}
407
408// TODO figure out how to find scratch len using mp_bases.
409//
410// # Worst-case complexity
411// $T(n, m) = O(nm \log (nm) \log\log (nm))$
412//
413// $M(n, m) = O(nm \log (nm))$
414//
415// where $T$ is time, $M$ is additional memory, $n$ is `xs.len()`, and $m$ is `exp`.
416//
417// This is equivalent to `mpn_pow_1` from `mpn/generic/pow_1.c`, GMP 6.2.1, where `exp > 1`, `bn >
418// 1`, and the last element of `xs` is nonzero.
419#[cfg(feature = "test_build")]
420fn limbs_pow_to_out_alt<'a>(
421    mut out: &'a mut [Limb],
422    xs: &[Limb],
423    exp: u64,
424    mut scratch: &'a mut [Limb],
425) -> usize {
426    let len = xs.len();
427    assert!(len > 1);
428    assert!(exp > 1);
429    // Count number of bits in exp, and compute where to put initial square in order to magically
430    // get results in the entry out.
431    let bits = exp.significant_bits();
432    if bits.eq_mod_power_of_2(CountOnes::count_ones(exp), 1) {
433        swap(&mut out, &mut scratch);
434    }
435    let mut square_scratch = vec![0; limbs_square_to_out_scratch_len(xs.len())];
436    limbs_square_to_out(out, xs, &mut square_scratch);
437    let mut out_len = len << 1;
438    if out[out_len - 1] == 0 {
439        out_len -= 1;
440    }
441    for i in (0..bits - 1).rev() {
442        if exp.get_bit(i) {
443            let mut mul_scratch = vec![0; limbs_mul_greater_to_out_scratch_len(out_len, len)];
444            if limbs_mul_greater_to_out(scratch, &out[..out_len], xs, &mut mul_scratch) == 0 {
445                out_len -= 1;
446            }
447            out_len += len;
448            swap(&mut out, &mut scratch);
449        }
450        if i == 0 {
451            break;
452        }
453        let mut square_scratch = vec![0; limbs_square_to_out_scratch_len(out_len)];
454        limbs_square_to_out(scratch, &out[..out_len], &mut square_scratch);
455        out_len <<= 1;
456        if scratch[out_len - 1] == 0 {
457            out_len -= 1;
458        }
459        swap(&mut out, &mut scratch);
460    }
461    out_len
462}
463
464// # Worst-case complexity
465// $T(n, m) = O(nm \log (nm) \log\log (nm))$
466//
467// $M(n, m) = O(nm \log (nm))$
468//
469// where $T$ is time, $M$ is additional memory, $n$ is `xs.len()`, and $m$ is `exp`.
470#[cfg(feature = "test_build")]
471fn limbs_pow_alt(xs: &[Limb], exp: u64) -> Vec<Limb> {
472    let mut out = vec![0; limbs_pow_alt_estimated_out_len(xs, exp)];
473    let mut scratch = vec![0; limbs_pow_alt_estimated_scratch_len(xs, exp)];
474    let out_len = limbs_pow_to_out_alt(&mut out, xs, exp, &mut scratch);
475    assert!(out_len <= out.len());
476    out.truncate(out_len);
477    out
478}
479
480#[cfg(feature = "test_build")]
481impl Natural {
482    pub fn pow_ref_alt(&self, exp: u64) -> Self {
483        match (self, exp) {
484            (_, 0) | (&Self::ONE, _) => Self::ONE,
485            (&Self::ZERO, _) => Self::ZERO,
486            (x, 1) => x.clone(),
487            (x, 2) => x.square(),
488            (x, exp) if x.is_power_of_2() => Self::power_of_2((x.significant_bits() - 1) * exp),
489            (Self(Small(small)), exp) => {
490                if small.significant_bits() * exp <= Limb::WIDTH {
491                    Self(Small(small.checked_pow(u32::wrapping_from(exp)).unwrap()))
492                } else {
493                    Self::from_owned_limbs_asc(limb_pow_alt(*small, exp))
494                }
495            }
496            (Self(Large(limbs)), exp) => Self::from_owned_limbs_asc(limbs_pow_alt(limbs, exp)),
497        }
498    }
499
500    pub fn pow_assign_alt(&mut self, exp: u64) {
501        match (&mut *self, exp) {
502            (x, 0) => *x = Self::ONE,
503            (_, 1) | (&mut (Self::ZERO | Self::ONE), _) => {}
504            (x, 2) => x.square_assign(),
505            (x, exp) if x.is_power_of_2() => {
506                *x = Self::power_of_2((x.significant_bits() - 1) * exp);
507            }
508            (Self(Small(small)), exp) => {
509                if small.significant_bits() * exp <= Limb::WIDTH {
510                    *small = small.checked_pow(u32::wrapping_from(exp)).unwrap();
511                } else {
512                    *self = Self::from_owned_limbs_asc(limb_pow_alt(*small, exp));
513                }
514            }
515            (Self(Large(limbs)), exp) => {
516                *self = Self::from_owned_limbs_asc(limbs_pow_alt(limbs, exp));
517            }
518        }
519    }
520}
521
522impl Pow<u64> for Natural {
523    type Output = Self;
524
525    /// Raises a [`Natural`] to a power, taking the [`Natural`] by value.
526    ///
527    /// $f(x, n) = x^n$.
528    ///
529    /// # Worst-case complexity
530    /// $T(n, m) = O(nm \log (nm) \log\log (nm))$
531    ///
532    /// $M(n, m) = O(nm \log (nm))$
533    ///
534    /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and $m$ is
535    /// `exp`.
536    ///
537    /// # Examples
538    /// ```
539    /// use core::str::FromStr;
540    /// use malachite_base::num::arithmetic::traits::Pow;
541    /// use malachite_nz::natural::Natural;
542    ///
543    /// assert_eq!(
544    ///     Natural::from(3u32).pow(100).to_string(),
545    ///     "515377520732011331036461129765621272702107522001"
546    /// );
547    /// assert_eq!(
548    ///     Natural::from_str("12345678987654321")
549    ///         .unwrap()
550    ///         .pow(3)
551    ///         .to_string(),
552    ///     "1881676411868862234942354805142998028003108518161"
553    /// );
554    /// ```
555    #[inline]
556    fn pow(mut self, exp: u64) -> Self {
557        self.pow_assign(exp);
558        self
559    }
560}
561
562impl Pow<u64> for &Natural {
563    type Output = Natural;
564
565    /// Raises a [`Natural`] to a power, taking the [`Natural`] by reference.
566    ///
567    /// $f(x, n) = x^n$.
568    ///
569    /// # Worst-case complexity
570    /// $T(n, m) = O(nm \log (nm) \log\log (nm))$
571    ///
572    /// $M(n, m) = O(nm \log (nm))$
573    ///
574    /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and $m$ is
575    /// `exp`.
576    ///
577    /// # Examples
578    /// ```
579    /// use core::str::FromStr;
580    /// use malachite_base::num::arithmetic::traits::Pow;
581    /// use malachite_nz::natural::Natural;
582    ///
583    /// assert_eq!(
584    ///     (&Natural::from(3u32)).pow(100).to_string(),
585    ///     "515377520732011331036461129765621272702107522001"
586    /// );
587    /// assert_eq!(
588    ///     (&Natural::from_str("12345678987654321").unwrap())
589    ///         .pow(3)
590    ///         .to_string(),
591    ///     "1881676411868862234942354805142998028003108518161"
592    /// );
593    /// ```
594    #[inline]
595    fn pow(self, exp: u64) -> Natural {
596        match (self, exp) {
597            (_, 0) | (&Natural::ONE, _) => Natural::ONE,
598            (&Natural::ZERO, _) => Natural::ZERO,
599            (x, 1) => x.clone(),
600            (x, 2) => x.square(),
601            (Natural(Small(small)), exp) => {
602                if small.significant_bits() * exp <= Limb::WIDTH {
603                    Natural(Small(small.checked_pow(u32::wrapping_from(exp)).unwrap()))
604                } else {
605                    let mut out = Natural(Large(limbs_pow(&[*small], exp)));
606                    out.demote_if_small();
607                    out
608                }
609            }
610            (Natural(Large(limbs)), exp) => {
611                let mut out = Natural(Large(limbs_pow(limbs, exp)));
612                out.demote_if_small();
613                out
614            }
615        }
616    }
617}
618
619impl PowAssign<u64> for Natural {
620    /// Raises a [`Natural`] to a power in place.
621    ///
622    /// $x \gets x^n$.
623    ///
624    /// # Worst-case complexity
625    /// $T(n, m) = O(nm \log (nm) \log\log (nm))$
626    ///
627    /// $M(n, m) = O(nm \log (nm))$
628    ///
629    /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and $m$ is
630    /// `exp`.
631    ///
632    /// # Examples
633    /// ```
634    /// use core::str::FromStr;
635    /// use malachite_base::num::arithmetic::traits::PowAssign;
636    /// use malachite_nz::natural::Natural;
637    ///
638    /// let mut x = Natural::from(3u32);
639    /// x.pow_assign(100);
640    /// assert_eq!(
641    ///     x.to_string(),
642    ///     "515377520732011331036461129765621272702107522001"
643    /// );
644    ///
645    /// let mut x = Natural::from_str("12345678987654321").unwrap();
646    /// x.pow_assign(3);
647    /// assert_eq!(
648    ///     x.to_string(),
649    ///     "1881676411868862234942354805142998028003108518161"
650    /// );
651    /// ```
652    fn pow_assign(&mut self, exp: u64) {
653        match (&mut *self, exp) {
654            (x, 0) => *x = Self::ONE,
655            (_, 1) | (&mut (Self::ZERO | Self::ONE), _) => {}
656            (x, 2) => x.square_assign(),
657            (Self(Small(small)), exp) => {
658                if small.significant_bits() * exp <= Limb::WIDTH {
659                    *small = small.checked_pow(u32::wrapping_from(exp)).unwrap();
660                } else {
661                    *self = Self(Large(limbs_pow(&[*small], exp)));
662                    self.demote_if_small();
663                }
664            }
665            (Self(Large(limbs)), exp) => {
666                *self = Self(Large(limbs_pow(limbs, exp)));
667                self.demote_if_small();
668            }
669        }
670    }
671}