malachite_base/num/factorization/
is_power.rs

1// Copyright © 2025 William Youmans
2//
3// Uses code adopted from the FLINT Library.
4//
5//      Copyright © 2009 William Hart
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::num::arithmetic::traits::{
14    CheckedRoot, DivAssignMod, DivMod, GcdAssign, Parity, RootRem, SqrtRem,
15};
16use crate::num::basic::integers::USIZE_IS_U32;
17use crate::num::conversion::traits::{ExactFrom, WrappingFrom};
18use crate::num::factorization::primes::SMALL_PRIMES;
19use crate::num::factorization::traits::{
20    ExpressAsPower, Factor, IsPower, IsPrime, IsSquare, Primes,
21};
22use crate::num::logic::traits::{SignificantBits, TrailingZeros};
23
24// The following arrays are bitmasks indicating whether an integer is a 2, 3, or 5th power residue.
25// For example, modulo 31 we have:
26// - squares:    {0, 1, 2, 4, 5, 7, 8, 9, 10, 14, 16, 18, 19, 20, 25, 28}
27// - cubes:      {0, 1, 2, 4, 8, 15, 16, 23, 27, 29, 30}
28// - 5th powers: {0, 1, 5, 6, 25, 26, 30}
29// Since 2 is a square, cube, but not a 5th power mod 31, we encode it as 011 = 3. Then MOD31[2] =
30// 3.
31
32const MOD63: [u8; 63] = [
33    7, 7, 4, 0, 5, 4, 0, 5, 6, 5, 4, 4, 0, 4, 4, 0, 5, 4, 5, 4, 4, 0, 5, 4, 0, 5, 4, 6, 7, 4, 0, 4,
34    4, 0, 4, 6, 7, 5, 4, 0, 4, 4, 0, 5, 4, 4, 5, 4, 0, 5, 4, 0, 4, 4, 4, 6, 4, 0, 5, 4, 0, 4, 6,
35];
36
37const MOD61: [u8; 61] = [
38    7, 7, 0, 3, 1, 1, 0, 0, 2, 3, 0, 6, 1, 5, 5, 1, 1, 0, 0, 1, 3, 4, 1, 2, 2, 1, 0, 3, 2, 4, 0, 0,
39    4, 2, 3, 0, 1, 2, 2, 1, 4, 3, 1, 0, 0, 1, 1, 5, 5, 1, 6, 0, 3, 2, 0, 0, 1, 1, 3, 0, 7,
40];
41
42const MOD44: [u8; 44] = [
43    7, 7, 0, 2, 3, 3, 0, 2, 2, 3, 0, 6, 7, 2, 0, 2, 3, 2, 0, 2, 3, 6, 0, 6, 2, 3, 0, 2, 2, 2, 0, 2,
44    6, 7, 0, 2, 3, 3, 0, 2, 2, 2, 0, 6,
45];
46
47const MOD31: [u8; 31] =
48    [7, 7, 3, 0, 3, 5, 4, 1, 3, 1, 1, 0, 0, 0, 1, 2, 3, 0, 1, 1, 1, 0, 0, 2, 0, 5, 4, 2, 1, 2, 6];
49
50const MOD72: [u8; 72] = [
51    7, 7, 0, 0, 0, 7, 0, 7, 7, 7, 0, 7, 0, 7, 0, 0, 7, 7, 0, 7, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7,
52    7, 0, 0, 7, 0, 7, 0, 0, 7, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 7, 0, 7, 7, 0, 0, 7, 0, 7, 0, 7,
53    7, 7, 0, 7, 0, 0, 0, 7,
54];
55
56const MOD49: [u8; 49] = [
57    1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
58    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
59];
60
61const MOD67: [u8; 67] = [
62    2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0,
63    0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64    0, 0, 2,
65];
66
67const MOD79: [u8; 79] = [
68    4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0,
69    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0,
70    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
71];
72
73// This is n_is_power when FLINT64 is false, from ulong_extras/is_power.c, FLINT 3.1.2.
74fn get_perfect_power_u32(n: u32) -> Option<(u32, u64)> {
75    // Check for powers 2, 3, 5
76    let mut t = MOD31[(n % 31) as usize];
77    t &= MOD44[(n % 44) as usize];
78    t &= MOD61[(n % 61) as usize];
79    t &= MOD63[(n % 63) as usize];
80    // Check for perfect square
81    if t & 1 != 0 {
82        let (rt, rem) = n.sqrt_rem();
83        if rem == 0 {
84            return Some((rt, 2));
85        }
86    }
87    // Check for perfect cube
88    if t & 2 != 0 {
89        let (rt, rem) = n.root_rem(3);
90        if rem == 0 {
91            return Some((rt, 3));
92        }
93    }
94    // Check for perfect fifth power
95    if t & 4 != 0 {
96        let (rt, rem) = n.root_rem(5);
97        if rem == 0 {
98            return Some((rt, 5));
99        }
100    }
101    // Check for powers 7, 11, 13
102    t = MOD49[(n % 49) as usize];
103    t |= MOD67[(n % 67) as usize];
104    t |= MOD79[(n % 79) as usize];
105    t &= MOD72[(n % 72) as usize];
106
107    // Check for perfect 7th power
108    if t & 1 != 0 {
109        let (rt, rem) = n.root_rem(7);
110        if rem == 0 {
111            return Some((rt, 7));
112        }
113    }
114    // Check for perfect 11th power
115    if t & 2 != 0 {
116        let (rt, rem) = n.root_rem(11);
117        if rem == 0 {
118            return Some((rt, 11));
119        }
120    }
121    // Check for perfect 13th power
122    if t & 13 != 0 {
123        let (rt, rem) = n.root_rem(13);
124        if rem == 0 {
125            return Some((rt, 13));
126        }
127    }
128    // Handle powers of 2
129    let count = u64::from(n.trailing_zeros());
130    let mut n = n >> count;
131    if n == 1 {
132        return if count == 1 {
133            None // Just 2^1 = 2, not a perfect power
134        } else {
135            Some((2, count))
136        };
137    }
138    // Check other powers (exp >= 17, root <= 13 and odd)
139    let mut exp = 0;
140    while n.is_multiple_of(3) {
141        n /= 3;
142        exp += 1;
143    }
144    if exp > 0 {
145        if n == 1 && exp > 1 {
146            if count == 0 {
147                return Some((3, exp));
148            } else if count == exp {
149                return Some((6, exp));
150            } else if count == 2 * exp {
151                return Some((12, exp));
152            }
153        }
154        return None;
155    }
156    None
157}
158
159// This is n_is_power when FLINT64 is false, from ulong_extras/is_power.c, FLINT 3.1.2, returning
160// only whether n can be expressed as a nontrivial perfect power.
161fn get_perfect_power_u32_bool(n: u32) -> bool {
162    // Check for powers 2, 3, 5
163    let mut t = MOD31[(n % 31) as usize];
164    t &= MOD44[(n % 44) as usize];
165    t &= MOD61[(n % 61) as usize];
166    t &= MOD63[(n % 63) as usize];
167    // Check for perfect square
168    if t & 1 != 0 && n.is_square() {
169        return true;
170    }
171    // Check for perfect cube
172    if t & 2 != 0 && n.root_rem(3).1 == 0 {
173        return true;
174    }
175    // Check for perfect fifth power
176    if t & 4 != 0 && n.root_rem(5).1 == 0 {
177        return true;
178    }
179    // Check for powers 7, 11, 13
180    t = MOD49[(n % 49) as usize];
181    t |= MOD67[(n % 67) as usize];
182    t |= MOD79[(n % 79) as usize];
183    t &= MOD72[(n % 72) as usize];
184    // Check for perfect 7th power
185    if t & 1 != 0 && n.root_rem(7).1 == 0 {
186        return true;
187    }
188    // Check for perfect 11th power
189    if t & 2 != 0 && n.root_rem(11).1 == 0 {
190        return true;
191    }
192    // Check for perfect 13th power
193    if t & 13 != 0 && n.root_rem(13).1 == 0 {
194        return true;
195    }
196    // Handle powers of 2
197    let count = n.trailing_zeros();
198    let mut n = n >> n.trailing_zeros();
199    if n == 1 {
200        return count != 1;
201    }
202    // Check other powers (exp >= 17, root <= 13 and odd)
203    let mut exp = 0;
204    while n.is_multiple_of(3) {
205        n /= 3;
206        exp += 1;
207    }
208    exp > 0 && n == 1 && exp > 1 && (count == 0 || count == exp || count == exp << 1)
209}
210
211// This is n_is_power when FLINT64 is true, from ulong_extras/is_power.c, FLINT 3.1.2.
212fn get_perfect_power_u64(n: u64) -> Option<(u64, u64)> {
213    // Check for powers 2, 3, 5
214    let mut t = MOD31[(n % 31) as usize];
215    t &= MOD44[(n % 44) as usize];
216    t &= MOD61[(n % 61) as usize];
217    t &= MOD63[(n % 63) as usize];
218    // Check for perfect square
219    if t & 1 != 0 {
220        let (rt, rem) = n.sqrt_rem();
221        if rem == 0 {
222            return Some((rt, 2));
223        }
224    }
225    // Check for perfect cube
226    if t & 2 != 0 {
227        let (rt, rem) = n.root_rem(3);
228        if rem == 0 {
229            return Some((rt, 3));
230        }
231    }
232    // Check for perfect fifth power
233    if t & 4 != 0 {
234        let (rt, rem) = n.root_rem(5);
235        if rem == 0 {
236            return Some((rt, 5));
237        }
238    }
239    // Check for powers 7, 11, 13
240    t = MOD49[(n % 49) as usize];
241    t |= MOD67[(n % 67) as usize];
242    t |= MOD79[(n % 79) as usize];
243    t &= MOD72[(n % 72) as usize];
244    // Check for perfect 7th power
245    if t & 1 != 0 {
246        let (rt, rem) = n.root_rem(7);
247        if rem == 0 {
248            return Some((rt, 7));
249        }
250    }
251    // Check for perfect 11th power
252    if t & 2 != 0 {
253        let (rt, rem) = n.root_rem(11);
254        if rem == 0 {
255            return Some((rt, 11));
256        }
257    }
258    // Check for perfect 13th power
259    if t & 13 != 0 {
260        let (rt, rem) = n.root_rem(13);
261        if rem == 0 {
262            return Some((rt, 13));
263        }
264    }
265    // Handle powers of 2
266    let count = u64::from(n.trailing_zeros());
267    let mut n = n >> count;
268    if n == 1 {
269        return if count == 1 {
270            None // Just 2^1 = 2, not a perfect power
271        } else {
272            Some((2, count))
273        };
274    }
275    // Check other powers (exp >= 17, root <= 13 and odd)
276    let mut exp = 0;
277    while n.is_multiple_of(3) {
278        n /= 3;
279        exp += 1;
280    }
281    if exp > 0 {
282        if n == 1 && exp > 1 {
283            if count == 0 {
284                return Some((3, exp));
285            } else if count == exp {
286                return Some((6, exp));
287            } else if count == 2 * exp {
288                return Some((12, exp));
289            }
290        }
291        return None;
292    }
293    // Check powers of 5
294    exp = 0;
295    while n.is_multiple_of(5) {
296        n /= 5;
297        exp += 1;
298    }
299    if exp > 0 {
300        if n == 1 && exp > 1 {
301            if count == 0 {
302                return Some((5, exp));
303            } else if count == exp {
304                return Some((10, exp));
305            }
306        }
307        return None;
308    }
309    if count > 0 {
310        return None;
311    }
312    // Check powers of 7
313    exp = 0;
314    while n.is_multiple_of(7) {
315        n /= 7;
316        exp += 1;
317    }
318    if exp > 0 {
319        if n == 1 && exp > 1 {
320            return Some((7, exp));
321        }
322        return None;
323    }
324    // Check powers of 11
325    exp = 0;
326    while n.is_multiple_of(11) {
327        n /= 11;
328        exp += 1;
329    }
330    if exp > 0 {
331        if n == 1 && exp > 1 {
332            return Some((11, exp));
333        }
334        return None;
335    }
336    // Check powers of 13
337    exp = 0;
338    while n.is_multiple_of(13) {
339        n /= 13;
340        exp += 1;
341    }
342    if exp > 0 {
343        if n == 1 && exp > 1 {
344            return Some((13, exp));
345        }
346        return None;
347    }
348    None
349}
350
351// This is n_is_power when FLINT64 is true, from ulong_extras/is_power.c, FLINT 3.1.2, returning
352// only whether n can be expressed as a nontrivial perfect power.
353fn get_perfect_power_u64_bool(n: u64) -> bool {
354    // Check for powers 2, 3, 5
355    let mut t = MOD31[(n % 31) as usize];
356    t &= MOD44[(n % 44) as usize];
357    t &= MOD61[(n % 61) as usize];
358    t &= MOD63[(n % 63) as usize];
359    // Check for perfect square
360    if t & 1 != 0 && n.is_square() {
361        return true;
362    }
363    // Check for perfect cube
364    if t & 2 != 0 && n.root_rem(3).1 == 0 {
365        return true;
366    }
367    // Check for perfect fifth power
368    if t & 4 != 0 && n.root_rem(5).1 == 0 {
369        return true;
370    }
371    // Check for powers 7, 11, 13
372    t = MOD49[(n % 49) as usize];
373    t |= MOD67[(n % 67) as usize];
374    t |= MOD79[(n % 79) as usize];
375    t &= MOD72[(n % 72) as usize];
376    // Check for perfect 7th power
377    if t & 1 != 0 && n.root_rem(7).1 == 0 {
378        return true;
379    }
380    // Check for perfect 11th power
381    if t & 2 != 0 && n.root_rem(11).1 == 0 {
382        return true;
383    }
384    // Check for perfect 13th power
385    if t & 13 != 0 && n.root_rem(13).1 == 0 {
386        return true;
387    }
388    // Handle powers of 2
389    let count = u64::from(n.trailing_zeros());
390    let mut n = n >> count;
391    if n == 1 {
392        return count != 1;
393    }
394    // Check other powers (exp >= 17, root <= 13 and odd)
395    let mut exp = 0;
396    while n.is_multiple_of(3) {
397        n /= 3;
398        exp += 1;
399    }
400    if exp > 0 {
401        return n == 1 && exp > 1 && (count == 0 || count == exp || count == exp << 1);
402    }
403    // Check powers of 5
404    exp = 0;
405    while n.is_multiple_of(5) {
406        n /= 5;
407        exp += 1;
408    }
409    if exp > 0 {
410        return n == 1 && exp > 1 && (count == 0 || count == exp);
411    }
412    if count > 0 {
413        return false;
414    }
415    // Check powers of 7
416    exp = 0;
417    while n.is_multiple_of(7) {
418        n /= 7;
419        exp += 1;
420    }
421    if exp > 0 {
422        return n == 1 && exp > 1;
423    }
424    // Check powers of 11
425    exp = 0;
426    while n.is_multiple_of(11) {
427        n /= 11;
428        exp += 1;
429    }
430    if exp > 0 {
431        return n == 1 && exp > 1;
432    }
433    // Check powers of 13
434    exp = 0;
435    while n.is_multiple_of(13) {
436        n /= 13;
437        exp += 1;
438    }
439    n == 1 && exp > 1
440}
441
442fn get_perfect_power_u128(n: u128) -> Option<(u128, u64)> {
443    if let Ok(n) = u64::try_from(n) {
444        return get_perfect_power_u64(n).map(|(p, e)| (u128::from(p), e));
445    }
446    // Find largest power of 2 dividing n
447    let mut pow_2 = TrailingZeros::trailing_zeros(n);
448    // Two divides exactly once - not a perfect power
449    if pow_2 == 1 {
450        return None;
451    }
452    // If pow_2 is prime, just check if n is a perfect pow_2-th power
453    if pow_2.is_prime() {
454        return n.checked_root(pow_2).map(|root| (root, pow_2));
455    }
456    // Divide out 2^pow_2 to get the odd part
457    let mut q = n >> pow_2;
458    // Factor out powers of small primes
459    for &prime in SMALL_PRIMES[..168].iter().skip(1) {
460        let prime = u128::from(prime);
461        let (new_q, r) = q.div_mod(prime);
462        if r == 0 {
463            q = new_q;
464            if q.div_assign_mod(prime) != 0 {
465                return None; // prime divides exactly once, reject
466            }
467            let mut pow_p = 2u64;
468            loop {
469                let (new_q, r) = q.div_mod(prime);
470                if r == 0 {
471                    q = new_q;
472                    pow_p += 1;
473                } else {
474                    break;
475                }
476            }
477            pow_2.gcd_assign(pow_p);
478            if pow_2 == 1 {
479                return None; // we have multiplicity 1 of some factor
480            }
481            // As soon as pow_2 becomes prime, stop factoring
482            if q == 1 || pow_2.is_prime() {
483                return n.checked_root(pow_2).map(|root| (root, pow_2));
484            }
485        }
486    }
487    // After factoring, check remaining cases
488    if pow_2 == 0 {
489        // No factors found above; exhaustively check all prime exponents
490        let bits = n.significant_bits();
491        for nth in u64::primes() {
492            // Terminate if exponent exceeds bit length (n ^ (1 / nth) < 2 for nth > bits)
493            if nth > bits {
494                return None;
495            }
496            if let Some(root) = n.checked_root(nth) {
497                return Some((root, nth));
498            }
499        }
500    } else {
501        // Found some factors; only check prime divisors of pow_2
502        for (nth, _) in pow_2.factor() {
503            if let Some(root) = n.checked_root(nth) {
504                return Some((root, nth));
505            }
506        }
507    }
508    None
509}
510
511fn get_perfect_power_u128_bool(n: u128) -> bool {
512    if let Ok(n) = u64::try_from(n) {
513        return get_perfect_power_u64_bool(n);
514    }
515    // Find largest power of 2 dividing n
516    let mut pow_2 = TrailingZeros::trailing_zeros(n);
517    // Two divides exactly once - not a perfect power
518    if pow_2 == 1 {
519        return false;
520    }
521    // If pow_2 is prime, check if n is a perfect pow_2-th power
522    if pow_2.is_prime() {
523        return n.checked_root(pow_2).is_some();
524    }
525    // Divide out 2^pow_2 to get the odd part
526    let mut q = n >> pow_2;
527    // Factor out powers of small primes
528    for &prime in SMALL_PRIMES[..168].iter().skip(1) {
529        let prime = u128::from(prime);
530        let (new_q, r) = q.div_mod(prime);
531        if r == 0 {
532            q = new_q;
533            if q.div_assign_mod(prime) != 0 {
534                return false; // prime divides exactly once, reject
535            }
536            let mut pow_p = 2u64;
537            loop {
538                let (new_q, r) = q.div_mod(prime);
539                if r == 0 {
540                    q = new_q;
541                    pow_p += 1;
542                } else {
543                    break;
544                }
545            }
546            pow_2.gcd_assign(pow_p);
547            if pow_2 == 1 {
548                return false; // we have multiplicity 1 of some factor
549            }
550            // As soon as pow_2 becomes prime, stop factoring
551            if q == 1 || pow_2.is_prime() {
552                return n.checked_root(pow_2).is_some();
553            }
554        }
555    }
556    // After factoring, check remaining cases
557    if pow_2 == 0 {
558        // No factors found above; exhaustively check all prime exponents
559        let bits = n.significant_bits();
560        for nth in u64::primes() {
561            // Terminate if exponent exceeds bit length (n ^ (1 / nth) < 2 for nth > bits)
562            if nth > bits {
563                return false;
564            }
565            if n.checked_root(nth).is_some() {
566                return true;
567            }
568        }
569    } else {
570        // Found some factors; only check prime divisors of pow_2
571        for (nth, _) in pow_2.factor() {
572            if n.checked_root(nth).is_some() {
573                return true;
574            }
575        }
576    }
577    false
578}
579
580fn express_as_power_u32(n: u32) -> Option<(u32, u64)> {
581    if n <= 1 {
582        return Some((n, 2));
583    }
584    // continue until we have largest possible exponent
585    let (mut base, mut exp) = get_perfect_power_u32(n)?;
586    while base > 3 {
587        match get_perfect_power_u32(base) {
588            Some((base2, exp2)) => {
589                base = base2;
590                exp *= exp2;
591            }
592            None => {
593                return Some((base, exp));
594            }
595        }
596    }
597    Some((base, exp))
598}
599
600fn express_as_power_u64(n: u64) -> Option<(u64, u64)> {
601    if n <= 1 {
602        return Some((n, 2));
603    }
604    // continue until we have largest possible exponent
605    let (mut base, mut exp) = get_perfect_power_u64(n)?;
606    while base > 3 {
607        match get_perfect_power_u64(base) {
608            Some((base2, exp2)) => {
609                base = base2;
610                exp *= exp2;
611            }
612            None => {
613                return Some((base, exp));
614            }
615        }
616    }
617    Some((base, exp))
618}
619
620fn express_as_power_u128(n: u128) -> Option<(u128, u64)> {
621    if n <= 1 {
622        return Some((n, 2));
623    }
624    // continue until we have largest possible exponent
625    let (mut base, mut exp) = get_perfect_power_u128(n)?;
626    while base > 3 {
627        match get_perfect_power_u128(base) {
628            Some((base2, exp2)) => {
629                base = base2;
630                exp *= exp2;
631            }
632            None => {
633                return Some((base, exp));
634            }
635        }
636    }
637    Some((base, exp))
638}
639
640fn express_as_power_i32(n: i32) -> Option<(i32, u64)> {
641    if n == 0 || n == 1 {
642        return Some((n, 2));
643    }
644    // continue until we have largest possible exponent
645    let (mut base, mut exp) = get_perfect_power_u32(n.unsigned_abs())?;
646    while base > 3 {
647        match get_perfect_power_u32(base) {
648            Some((base2, exp2)) => {
649                base = base2;
650                exp *= exp2;
651            }
652            None => break,
653        }
654    }
655    // handle negative input
656    if n < 0 && exp.even() {
657        while exp.even() {
658            base *= base;
659            exp >>= 1;
660        }
661        if exp == 1 {
662            return None;
663        }
664    }
665    let ibase = i32::exact_from(base);
666    Some((if n >= 0 { ibase } else { -ibase }, exp))
667}
668
669fn express_as_power_i64(n: i64) -> Option<(i64, u64)> {
670    if n == 0 || n == 1 {
671        return Some((n, 2));
672    }
673    // continue until we have largest possible exponent
674    let (mut base, mut exp) = get_perfect_power_u64(n.unsigned_abs())?;
675    while base > 3 {
676        match get_perfect_power_u64(base) {
677            Some((base2, exp2)) => {
678                base = base2;
679                exp *= exp2;
680            }
681            None => break,
682        }
683    }
684    // handle negative input
685    if n < 0 && exp.even() {
686        while exp.even() {
687            base *= base;
688            exp >>= 1;
689        }
690        if exp == 1 {
691            return None;
692        }
693    }
694    let ibase = i64::exact_from(base);
695    Some((if n >= 0 { ibase } else { -ibase }, exp))
696}
697
698fn express_as_power_i128(n: i128) -> Option<(i128, u64)> {
699    if n == 0 || n == 1 {
700        return Some((n, 2));
701    }
702    // continue until we have largest possible exponent
703    let (mut base, mut exp) = get_perfect_power_u128(n.unsigned_abs())?;
704    while base > 3 {
705        match get_perfect_power_u128(base) {
706            Some((base2, exp2)) => {
707                base = base2;
708                exp *= exp2;
709            }
710            None => break,
711        }
712    }
713    // handle negative input
714    if n < 0 && exp.even() {
715        while exp.even() {
716            base *= base;
717            exp >>= 1;
718        }
719        if exp == 1 {
720            return None;
721        }
722    }
723    let ibase = i128::exact_from(base);
724    Some((if n >= 0 { ibase } else { -ibase }, exp))
725}
726
727#[inline]
728fn is_power_u32(n: u32) -> bool {
729    n <= 1 || get_perfect_power_u32_bool(n)
730}
731
732#[inline]
733fn is_power_u64(n: u64) -> bool {
734    n <= 1 || get_perfect_power_u64_bool(n)
735}
736
737fn is_power_i32(n: i32) -> bool {
738    if n == 0 || n == 1 {
739        return true;
740    }
741    if n > 0 {
742        // For positive numbers, just check if it's a perfect power
743        return get_perfect_power_u32_bool(n.unsigned_abs());
744    }
745    // For negative numbers, we need to check if there's an odd exponent representation
746    //
747    // continue until we have largest possible exponent
748    let (mut base, mut exp) = if let Some((base, exp)) = get_perfect_power_u32(n.unsigned_abs()) {
749        (base, exp)
750    } else {
751        return false;
752    };
753    while base > 3 {
754        match get_perfect_power_u32(base) {
755            Some((base2, exp2)) => {
756                base = base2;
757                exp *= exp2;
758            }
759            None => break,
760        }
761    }
762    // Check if we can make the exponent odd
763    !exp.is_power_of_two()
764}
765
766fn is_power_i64(n: i64) -> bool {
767    if n == 0 || n == 1 {
768        return true;
769    }
770    if n > 0 {
771        // For positive numbers, just check if it's a perfect power
772        return get_perfect_power_u64_bool(n.unsigned_abs());
773    }
774    // For negative numbers, we need to check if there's an odd exponent representation
775    //
776    // continue until we have largest possible exponent
777    let (mut base, mut exp) = if let Some((base, exp)) = get_perfect_power_u64(n.unsigned_abs()) {
778        (base, exp)
779    } else {
780        return false;
781    };
782    while base > 3 {
783        match get_perfect_power_u64(base) {
784            Some((base2, exp2)) => {
785                base = base2;
786                exp *= exp2;
787            }
788            None => break,
789        }
790    }
791    // Check if we can make the exponent odd
792    !exp.is_power_of_two()
793}
794
795fn is_power_i128(n: i128) -> bool {
796    if n == 0 || n == 1 {
797        return true;
798    }
799    if n > 0 {
800        // For positive numbers, just check if it's a perfect power
801        return get_perfect_power_u128_bool(n.unsigned_abs());
802    }
803    // For negative numbers, we need to check if there's an odd exponent representation
804    //
805    // continue until we have largest possible exponent
806    let (mut base, mut exp) = if let Some((base, exp)) = get_perfect_power_u128(n.unsigned_abs()) {
807        (base, exp)
808    } else {
809        return false;
810    };
811    while base > 3 {
812        match get_perfect_power_u128(base) {
813            Some((base2, exp2)) => {
814                base = base2;
815                exp *= exp2;
816            }
817            None => break,
818        }
819    }
820    // Check if we can make the exponent odd
821    !exp.is_power_of_two()
822}
823
824impl ExpressAsPower for u64 {
825    /// Expresses a number as a perfect power, if such a representation exists. We define a perfect
826    /// power as any number of the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In
827    /// particular, 0 and 1 are considered perfect powers. If a number has more than one
828    /// representation as a power, the representation with the smallest base is returned. For
829    /// example, $64=2^6=4^3=8^2$, but this function returns `(2,6)` rather than `(4,3)` or `(8,2)`.
830    ///
831    /// # Worst-case complexity
832    /// Constant time and additional memory.
833    ///
834    /// # Examples
835    /// See [here](super::is_power#express_as_power).
836    ///
837    /// # Notes
838    /// - This returns an [`Option`] which is either `Some((base, exp))` if the input is a perfect
839    ///   power equal to $\text{base}^\text{exp}$, otherwise `None`.
840    /// - For 0 this returns `Some((0, 2))` and for 1 this returns `Some((1, 2))`.
841    #[inline]
842    fn express_as_power(&self) -> Option<(u64, u64)> {
843        express_as_power_u64(*self)
844    }
845}
846
847impl ExpressAsPower for u128 {
848    /// Expresses a number as a perfect power, if such a representation exists. We define a perfect
849    /// power as any number of the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In
850    /// particular, 0 and 1 are considered perfect powers. If a number has more than one
851    /// representation as a power, the representation with the smallest base is returned. For
852    /// example, $64=2^6=4^3=8^2$, but this function returns `(2,6)` rather than `(4,3)` or `(8,2)`.
853    ///
854    /// # Worst-case complexity
855    /// Constant time and additional memory.
856    ///
857    /// # Examples
858    /// See [here](super::is_power#express_as_power).
859    ///
860    /// # Notes
861    /// - This returns an [`Option`] which is either `Some((base, exp))` if the input is a perfect
862    ///   power equal to $\text{base}^\text{exp}$, otherwise `None`.
863    /// - For 0 this returns `Some((0, 2))` and for 1 this returns `Some((1, 2))`.
864    #[inline]
865    fn express_as_power(&self) -> Option<(Self, u64)> {
866        express_as_power_u128(*self)
867    }
868}
869
870impl ExpressAsPower for usize {
871    /// Expresses a number as a perfect power, if such a representation exists. We define a perfect
872    /// power as any number of the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In
873    /// particular, 0 and 1 are considered perfect powers. If a number has more than one
874    /// representation as a power, the representation with the smallest base is returned. For
875    /// example, $64=2^6=4^3=8^2$, but this function returns `(2,6)` rather than `(4,3)` or `(8,2)`.
876    ///
877    /// # Worst-case complexity
878    /// Constant time and additional memory.
879    ///
880    /// # Examples
881    /// See [here](super::is_power#express_as_power).
882    ///
883    /// # Notes
884    /// - This returns an [`Option`] which is either `Some((base, exp))` if the input is a perfect
885    ///   power equal to $\text{base}^\text{exp}$, otherwise `None`.
886    /// - For 0 this returns `Some((0, 2))` and for 1 this returns `Some((1, 2))`.
887    fn express_as_power(&self) -> Option<(Self, u64)> {
888        if USIZE_IS_U32 {
889            match express_as_power_u32(u32::wrapping_from(*self)) {
890                Some((base, exp)) => Some((Self::wrapping_from(base), exp)),
891                _ => None,
892            }
893        } else {
894            match express_as_power_u64(u64::wrapping_from(*self)) {
895                Some((base, exp)) => Some((Self::wrapping_from(base), exp)),
896                _ => None,
897            }
898        }
899    }
900}
901
902impl IsPower for u64 {
903    /// Determines whether an integer is a perfect power. We define a perfect power as any number of
904    /// the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In particular 0 and 1 are
905    /// considered perfect powers.
906    ///
907    /// $f(x) = (\exists b \in \Z, e \in \N : e > 1 \ \text{and} \ b^e = x)$.
908    ///
909    /// # Worst-case complexity
910    /// Constant time and additional memory.
911    ///
912    /// # Examples
913    /// See [here](super::is_power#is_power).
914    #[inline]
915    fn is_power(&self) -> bool {
916        is_power_u64(*self)
917    }
918}
919
920impl IsPower for u128 {
921    /// Determines whether an integer is a perfect power. We define a perfect power as any number of
922    /// the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In particular 0 and 1 are
923    /// considered perfect powers.
924    ///
925    /// $f(x) = (\exists b \in \Z, e \in \N : e > 1 \ \text{and} \ b^e = x)$.
926    ///
927    /// # Worst-case complexity
928    /// Constant time and additional memory.
929    ///
930    /// # Examples
931    /// See [here](super::is_power#is_power).
932    #[inline]
933    fn is_power(&self) -> bool {
934        get_perfect_power_u128_bool(*self)
935    }
936}
937
938impl IsPower for usize {
939    /// Determines whether an integer is a perfect power. We define a perfect power as any number of
940    /// the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In particular 0 and 1 are
941    /// considered perfect powers.
942    ///
943    /// $f(x) = (\exists b \in \Z, e \in \N : e > 1 \ \text{and} \ b^e = x)$.
944    ///
945    /// # Worst-case complexity
946    /// Constant time and additional memory.
947    ///
948    /// # Examples
949    /// See [here](super::is_power#is_power).
950    fn is_power(&self) -> bool {
951        if USIZE_IS_U32 {
952            is_power_u32(u32::wrapping_from(*self))
953        } else {
954            is_power_u64(u64::wrapping_from(*self))
955        }
956    }
957}
958
959macro_rules! impl_unsigned_32 {
960    ($t: ident) => {
961        impl ExpressAsPower for $t {
962            /// Expresses a number as a perfect power, if such a representation exists. We define a
963            /// perfect power as any number of the form $a^x$ where $x > 1$, with $a$ and $x$ both
964            /// integers. In particular, 0 and 1 are considered perfect powers. If a number has more
965            /// than one representation as a power, the representation with the smallest base is
966            /// returned. For example, $64=2^6=4^3=8^2$, but this function returns `(2,6)` rather
967            /// than `(4,3)` or `(8,2)`.
968            ///
969            /// # Worst-case complexity
970            /// Constant time and additional memory.
971            ///
972            /// # Examples
973            /// See [here](super::is_power#express_as_power).
974            ///
975            /// # Notes
976            /// - This returns an [`Option`] which is either `Some((base, exp))` if the input is a
977            ///   perfect power equal to $\text{base}^\text{exp}$, otherwise `None`.
978            /// - For 0 this returns `Some((0, 2))` and for 1 this returns `Some((1, 2))`.
979            fn express_as_power(&self) -> Option<($t, u64)> {
980                match express_as_power_u32(u32::from(*self)) {
981                    Some((base, exp)) => Some(($t::exact_from(base), exp)),
982                    _ => None,
983                }
984            }
985        }
986
987        impl IsPower for $t {
988            /// Determines whether an integer is a perfect power. We define a perfect power as any
989            /// number of the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In
990            /// particular 0 and 1 are considered perfect powers.
991            ///
992            /// $f(x) = (\exists b \in \Z, e \in \N : e > 1 \ \text{and} \ b^e = x)$.
993            ///
994            /// # Worst-case complexity
995            /// Constant time and additional memory.
996            ///
997            /// # Examples
998            /// See [here](super::is_power#is_power).
999            #[inline]
1000            fn is_power(&self) -> bool {
1001                is_power_u32(u32::from(*self))
1002            }
1003        }
1004    };
1005}
1006impl_unsigned_32!(u8);
1007impl_unsigned_32!(u16);
1008impl_unsigned_32!(u32);
1009
1010impl ExpressAsPower for i64 {
1011    /// Expresses a number as a perfect power, if such a representation exists. We define a perfect
1012    /// power as any number of the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In
1013    /// particular, 0 and 1 are considered perfect powers. If a number has more than one
1014    /// representation as a power, the representation with the smallest base is returned. For
1015    /// example, $64=2^6=4^3=8^2$, but this function returns `(2,6)` rather than `(4,3)` or `(8,2)`.
1016    ///
1017    /// # Worst-case complexity
1018    /// Constant time and additional memory.
1019    ///
1020    /// # Examples
1021    /// See [here](super::is_power#express_as_power).
1022    ///
1023    /// # Notes
1024    /// - This returns an [`Option`] which is either `Some((base, exp))` if the input is a perfect
1025    ///   power equal to $\text{base}^\text{exp}$, otherwise `None`.
1026    /// - For 0 this returns `Some((0, 2))` and for 1 this returns `Some((1, 2))`.
1027    #[inline]
1028    fn express_as_power(&self) -> Option<(Self, u64)> {
1029        express_as_power_i64(*self)
1030    }
1031}
1032
1033impl ExpressAsPower for i128 {
1034    /// Expresses a number as a perfect power, if such a representation exists. We define a perfect
1035    /// power as any number of the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In
1036    /// particular, 0 and 1 are considered perfect powers. If a number has more than one
1037    /// representation as a power, the representation with the smallest base is returned. For
1038    /// example, $64=2^6=4^3=8^2$, but this function returns `(2,6)` rather than `(4,3)` or `(8,2)`.
1039    ///
1040    /// # Worst-case complexity
1041    /// Constant time and additional memory.
1042    ///
1043    /// # Examples
1044    /// See [here](super::is_power#express_as_power).
1045    ///
1046    /// # Notes
1047    /// - This returns an [`Option`] which is either `Some((base, exp))` if the input is a perfect
1048    ///   power equal to $\text{base}^\text{exp}$, otherwise `None`.
1049    /// - For 0 this returns `Some((0, 2))` and for 1 this returns `Some((1, 2))`.
1050    #[inline]
1051    fn express_as_power(&self) -> Option<(Self, u64)> {
1052        express_as_power_i128(*self)
1053    }
1054}
1055
1056impl ExpressAsPower for isize {
1057    /// Expresses a number as a perfect power, if such a representation exists. We define a perfect
1058    /// power as any number of the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In
1059    /// particular, 0 and 1 are considered perfect powers. If a number has more than one
1060    /// representation as a power, the representation with the smallest base is returned. For
1061    /// example, $64=2^6=4^3=8^2$, but this function returns `(2,6)` rather than `(4,3)` or `(8,2)`.
1062    ///
1063    /// # Worst-case complexity
1064    /// Constant time and additional memory.
1065    ///
1066    /// # Examples
1067    /// See [here](super::is_power#express_as_power).
1068    ///
1069    /// # Notes
1070    /// - This returns an [`Option`] which is either `Some((base, exp))` if the input is a perfect
1071    ///   power equal to $\text{base}^\text{exp}$, otherwise `None`.
1072    /// - For 0 this returns `Some((0, 2))` and for 1 this returns `Some((1, 2))`.
1073    fn express_as_power(&self) -> Option<(Self, u64)> {
1074        if USIZE_IS_U32 {
1075            match express_as_power_i32(i32::wrapping_from(*self)) {
1076                Some((base, exp)) => Some((Self::wrapping_from(base), exp)),
1077                _ => None,
1078            }
1079        } else {
1080            match express_as_power_i64(i64::wrapping_from(*self)) {
1081                Some((base, exp)) => Some((Self::wrapping_from(base), exp)),
1082                _ => None,
1083            }
1084        }
1085    }
1086}
1087
1088impl IsPower for i64 {
1089    /// Determines whether an integer is a perfect power. We define a perfect power as any number of
1090    /// the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In particular 0 and 1 are
1091    /// considered perfect powers.
1092    ///
1093    /// $f(x) = (\exists b \in \Z, e \in \N : e > 1 \ \text{and} \ b^e = x)$.
1094    ///
1095    /// # Worst-case complexity
1096    /// Constant time and additional memory.
1097    ///
1098    /// # Examples
1099    /// See [here](super::is_power#is_power).
1100    #[inline]
1101    fn is_power(&self) -> bool {
1102        is_power_i64(*self)
1103    }
1104}
1105
1106impl IsPower for i128 {
1107    /// Determines whether an integer is a perfect power. We define a perfect power as any number of
1108    /// the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In particular 0 and 1 are
1109    /// considered perfect powers.
1110    ///
1111    /// $f(x) = (\exists b \in \Z, e \in \N : e > 1 \ \text{and} \ b^e = x)$.
1112    ///
1113    /// # Worst-case complexity
1114    /// Constant time and additional memory.
1115    ///
1116    /// # Examples
1117    /// See [here](super::is_power#is_power).
1118    #[inline]
1119    fn is_power(&self) -> bool {
1120        is_power_i128(*self)
1121    }
1122}
1123
1124impl IsPower for isize {
1125    /// Determines whether an integer is a perfect power. We define a perfect power as any number of
1126    /// the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In particular 0 and 1 are
1127    /// considered perfect powers.
1128    ///
1129    /// $f(x) = (\exists b \in \Z, e \in \N : e > 1 \ \text{and} \ b^e = x)$.
1130    ///
1131    /// # Worst-case complexity
1132    /// Constant time and additional memory.
1133    ///
1134    /// # Examples
1135    /// See [here](super::is_power#is_power).
1136    fn is_power(&self) -> bool {
1137        if USIZE_IS_U32 {
1138            is_power_i32(i32::wrapping_from(*self))
1139        } else {
1140            is_power_i64(i64::wrapping_from(*self))
1141        }
1142    }
1143}
1144
1145macro_rules! impl_signed_32 {
1146    ($t: ident) => {
1147        impl ExpressAsPower for $t {
1148            /// Expresses a number as a perfect power, if such a representation exists. We define a
1149            /// perfect power as any number of the form $a^x$ where $x > 1$, with $a$ and $x$ both
1150            /// integers. In particular, 0 and 1 are considered perfect powers. If a number has more
1151            /// than one representation as a power, the representation with the smallest base is
1152            /// returned. For example, $64=2^6=4^3=8^2$, but this function returns `(2,6)` rather
1153            /// than `(4,3)` or `(8,2)`.
1154            ///
1155            /// # Worst-case complexity
1156            /// Constant time and additional memory.
1157            ///
1158            /// # Examples
1159            /// See [here](super::is_power#express_as_power).
1160            ///
1161            /// # Notes
1162            /// - This returns an [`Option`] which is either `Some((base, exp))` if the input is a
1163            ///   perfect power equal to $\text{base}^\text{exp}$, otherwise `None`.
1164            /// - For 0 this returns `Some((0, 2))` and for 1 this returns `Some((1, 2))`.
1165            fn express_as_power(&self) -> Option<($t, u64)> {
1166                match express_as_power_i32(i32::from(*self)) {
1167                    Some((base, exp)) => Some(($t::exact_from(base), exp)),
1168                    _ => None,
1169                }
1170            }
1171        }
1172
1173        impl IsPower for $t {
1174            /// Determines whether an integer is a perfect power. We define a perfect power as any
1175            /// number of the form $a^x$ where $x > 1$, with $a$ and $x$ both integers. In
1176            /// particular 0 and 1 are considered perfect powers.
1177            ///
1178            /// $f(x) = (\exists b \in \Z, e \in \N : e > 1 \ \text{and} \ b^e = x)$.
1179            ///
1180            /// # Worst-case complexity
1181            /// Constant time and additional memory.
1182            ///
1183            /// # Examples
1184            /// See [here](super::is_power#is_power).
1185            #[inline]
1186            fn is_power(&self) -> bool {
1187                is_power_i32(i32::from(*self))
1188            }
1189        }
1190    };
1191}
1192impl_signed_32!(i8);
1193impl_signed_32!(i16);
1194impl_signed_32!(i32);