Perfect Power Predicate

March 13, 2012

A number n is a perfect power if there exists a b and e for which be = n. For instance 216 = 63 = 23 · 33 is a perfect power, but 72 = 23 · 32 is not. Testing for perfect powers is similar to other powering predicates we have seen, and is useful in some factoring algorithms.

The trick to determining if a number is a perfect power is to know that, if the number is a perfect power, then the exponent e must be less than log2n, because if e is greater then 2e will be greater than n. Further, it is only necessary to test prime es, because if a number is a perfect power to a composite exponent it will also be a perfect power to the prime factors of the composite component; for instance, 215 = 32768 = 323 = 85 is a perfect cube root and also a perfect fifth root.

Your task is to write a function to determine if a number is a perfect power. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

And if the gcd of the counts of all the prime factors is greater than 1, it’s a perfect power. (Unless my brain is being very slow this morning.)

“foo=: 3 : ‘blah'” is just function-definition boilerplate.

The details of that inscrutable-looking “#/.~” are interesting, at least to me. “#” is count. “~” is reflexive call: “f~ x” is “x f x”. “/.” is a “keyed operation”. Given “x f/.y”, the unique items of x (the “key”) are used to break y into groups, then the function f is applied to each group. So, here we’re using the list of factors to classify itself, then we’re counting the number of values in each group. It’s an interesting higher-order function that I’ve not seen in too many places. The rather terse J documentation on it is here: http://jsoftware.com/help/dictionary/d421.htm.

Johann and Mike: Those functions work if you can factor n. But if n is the product of two large primes, it’s unlikely that you will get an answer any time soon. You could assume that if you can’t factor n in some reasonable time, it’s not a perfect power, but if n is the square of two large primes, you’re in trouble. For instance, is 148675665359980297048795508874724049089546782584077934753925649 a perfect power?

Basically, start with the smallest base and the largest exponent. If b**e is too large decrease the exponent. If b**e is too small increase the base. Repeat until b**e == n or all the exponents have been tried.

OP: Factoring is difficult, but won’t the prime sieve also suffer from a time/memory issue if the input is a large prime squared? Sieving all primes up to 12193263113702594790275394159593 (to match your example (thanks wolframalpha)) would take a lot of memory and time… Once you had this table though, your root search seems to be the most efficient of anyone’s posted.

My algorithm also chokes horribly on very large input (greater than 64 bit integers). I even tried integrating perl’s arbitrary precision library, but I failed miserably

A version in Perl that runs much faster than the Perl version above, and handles bigints. Given that the *reason* for a is_perfect_power function is typically as an initial step in factoring or primality testing (e.g. SQUFOF, AKS), using factoring to answer the question is a non-starter.

Doing just the bigint part (the is_perfect_power_simple function) is simpler, isolated from quirks of the C library and some old Perl (pre 5.8.8) screwiness with 64-bit numbers, and still reasonably fast. The native ints/floats method is ~400x faster on my computer so worth thinking about.