/* mpz_perfect_power_p(arg) -- Return non-zero if ARG is a perfect power, zero otherwise. Copyright 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ /* We are to determine if c is a perfect power, c = a ^ b. Assume c is divisible by 2^n and that codd = c/2^n is odd. Assume a is divisible by 2^m and that aodd = a/2^m is odd. It is always true that m divides n. * If n is prime, either 1) a is 2*aodd and b = n or 2) a = c and b = 1. So for n prime, we readily have a solution. * If n is factorable into the non-trivial factors p1,p2,... Since m divides n, m has a subset of n's factors and b = n / m. */ /* This is a naive approach to recognizing perfect powers. Many things can be improved. In particular, we should use p-adic arithmetic for computing possible roots. */ #include /* for NULL */ #include "gmp.h" #include "gmp-impl.h" #include "longlong.h" static unsigned long int gcd _PROTO ((unsigned long int a, unsigned long int b)); static int isprime _PROTO ((unsigned long int t)); static const unsigned short primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,101,103,107,109,113,127,131, 137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223, 227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311, 313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409, 419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503, 509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613, 617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719, 727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827, 829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941, 947,953,967,971,977,983,991,997,0 }; #define SMALLEST_OMITTED_PRIME 1009 int mpz_perfect_power_p (mpz_srcptr u) { unsigned long int prime; unsigned long int n, n2; int i; unsigned long int rem; mpz_t u2, q; int exact; mp_size_t uns; mp_size_t usize = SIZ (u); TMP_DECL; if (usize == 0) return 1; /* consider 0 a perfect power */ n2 = mpz_scan1 (u, 0); if (n2 == 1) return 0; /* 2 divides exactly once. */ if (n2 != 0 && (n2 & 1) == 0 && usize < 0) return 0; /* 2 has even multiplicity with negative U */ TMP_MARK; uns = ABS (usize) - n2 / BITS_PER_MP_LIMB; MPZ_TMP_INIT (q, uns); MPZ_TMP_INIT (u2, uns); mpz_tdiv_q_2exp (u2, u, n2); if (isprime (n2)) goto n2prime; for (i = 1; primes[i] != 0; i++) { prime = primes[i]; if (mpz_divisible_ui_p (u2, prime)) /* divisible by this prime? */ { rem = mpz_tdiv_q_ui (q, u2, prime * prime); if (rem != 0) { TMP_FREE; return 0; /* prime divides exactly once, reject */ } mpz_swap (q, u2); for (n = 2;;) { rem = mpz_tdiv_q_ui (q, u2, prime); if (rem != 0) break; mpz_swap (q, u2); n++; } if ((n & 1) == 0 && usize < 0) { TMP_FREE; return 0; /* even multiplicity with negative U, reject */ } n2 = gcd (n2, n); if (n2 == 1) { TMP_FREE; return 0; /* we have multiplicity 1 of some factor */ } if (mpz_cmpabs_ui (u2, 1) == 0) { TMP_FREE; return 1; /* factoring completed; consistent power */ } /* As soon as n2 becomes a prime number, stop factoring. Either we have u=x^n2 or u is not a perfect power. */ if (isprime (n2)) goto n2prime; } } if (n2 == 0) { /* We found no factors above; have to check all values of n. */ unsigned long int nth; for (nth = usize < 0 ? 3 : 2;; nth++) { if (! isprime (nth)) continue; #if 0 exact = mpz_padic_root (q, u2, nth, PTH); if (exact) #endif exact = mpz_root (q, u2, nth); if (exact) { TMP_FREE; return 1; } if (mpz_cmp_ui (q, SMALLEST_OMITTED_PRIME) < 0) { TMP_FREE; return 0; } } } else { unsigned long int nth; /* We found some factors above. We just need to consider values of n that divides n2. */ for (nth = 2; nth <= n2; nth++) { if (! isprime (nth)) continue; if (n2 % nth != 0) continue; #if 0 exact = mpz_padic_root (q, u2, nth, PTH); if (exact) #endif exact = mpz_root (q, u2, nth); if (exact) { TMP_FREE; return 1; } if (mpz_cmp_ui (q, SMALLEST_OMITTED_PRIME) < 0) { TMP_FREE; return 0; } } TMP_FREE; return 0; } n2prime: exact = mpz_root (NULL, u2, n2); TMP_FREE; return exact; } static unsigned long int gcd (unsigned long int a, unsigned long int b) { int an2, bn2, n2; if (a == 0) return b; if (b == 0) return a; count_trailing_zeros (an2, a); a >>= an2; count_trailing_zeros (bn2, b); b >>= bn2; n2 = MIN (an2, bn2); while (a != b) { if (a > b) { a -= b; do a >>= 1; while ((a & 1) == 0); } else /* b > a. */ { b -= a; do b >>= 1; while ((b & 1) == 0); } } return a << n2; } static int isprime (unsigned long int t) { unsigned long int q, r, d; if (t < 3 || (t & 1) == 0) return t == 2; for (d = 3, r = 1; r != 0; d += 2) { q = t / d; r = t - q * d; if (q < d) return 1; } return 0; }