1use 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
48const HALF_MAX: Limb = (1 << (Limb::WIDTH >> 1)) - 1;
50
51pub_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
64fn len_1_helper(x_0: &mut Limb, out_0: &mut Limb, trailing_zero_bits_out: &mut u64, exp: &mut u64) {
71 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 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
97fn 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 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 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 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 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 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 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 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 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#[cfg(feature = "test_build")]
278fn exp_predecessor(exp: u64) -> u64 {
279 if exp.even() { exp >> 1 } else { exp - 1 }
280}
281
282#[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#[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#[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#[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 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#[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#[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#[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#[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#[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 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#[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 #[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 #[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 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}