I’m looking for an algorithm (or better yet, code!) for a the generation of powers, specifically numbers with an odd exponent greater than 1: third powers, fifth powers, seventh powers, and so forth. My desired output is then
8, 27, 32, 125, 128, 216, 243, 343, 512, 1000
and so forth up to a specified limit.
I don’t want to store the powers in a list and sort them, because I’m making too many to fit in memory — hopefully the limit be 1030 or so, corresponding to a memory requirement of ≈ 1 TB.
My basic idea is to have an array holding the current number (starting at 2) for each exponent, starting with 3 and going up to the binary log of the limit. At each step I loop through the exponent array, finding the one which yields the smallest power (finding either pow(base, exponent) or more likely exponent * log(base), probably memoizing these values). At that point call the ‘output’ function, which will actually do calculations with the number but of course you don’t need to worry about that.
Of course because of the range of the numbers involved, bignums must be used — built into the language, in a library, or self-rolled. Relevant code or code snippets would be appreciated: I feel that this task is similar to some classic problems (e.g., Hamming’s problem of generating numbers that are of the form 2x3y5z) and can be solved efficiently. I’m fairly language-agnostic here: all I’ll need for my ‘output’ function are arrays, subtraction, bignum-word comparison, and a bignum integer square root function.
Your example is missing 64=4^3, and 729=9^3.
You want the set of all { n^m } traversed in numerical order, m odd, n integral and n > 1. We know that (for n > 1) that increasing either n or m will increase this value, but short of calculation we can’t compare much else.
There are two obvious “dual” ways to do this: keep track of the highest base n you consider, and for all bases less than that, the next exponent m to consider. Then pick the smallest one, and compare it to n^3. Or, the other way around — keep track of the highest exponent m, and for each exponent smaller than that, keep track of the highest base used, and find the smallest one, and compare it to adding 2^m.
To make keeping track of these numbers efficiently, you’ll want to keep them in a priority queue. Now, you still want to minimize the number of entries in the priority queue at a time, so we’ll want to figure out which of these two methods does better job of this. It turns out that much higher n values are required to make it to a given point. At number k, the largest value of m seen will be log_2 of k, whereas the largest value of n seen will be k^(1/3).
So, we have a priority queue with elements (v, n, m), where the value v=n^m.
Note that we need to check for v1 = v: we can have 2^9 = 512 = 8^3, and only one should be printed out, right?
A Haskell implementation, with a random priority queue grabbed off of hackage.
I have a run currently at 177403008736354688547625 (that’s 23 digits) and 1.3 GB plaintext output, after 8 minutes