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