There have been a number of questions asking for comments on code for the Project Euler problem to compute the largest prime factor of a number. A primary intent of this task is to find the factor as quickly as possible.
I decided to implement the code in C++ using at least some approximation of the best techniques/algorithms of which I was aware1.
#include <iostream>
#include <vector>
#include <time.h>
typedef unsigned long long integer;
const integer input = 60085147514377;
class prime_table {
std::vector<integer> primes;
public:
prime_table(integer num) {
integer max = ceil(sqrt(num));
std::vector<bool> table;
table.resize(max, false);
for (int i = 2; i < max; i++) {
if (!table[i]) {
primes.push_back(i);
for (integer temp = 2 * i; temp < max; temp += i)
table[temp] = true;
}
}
}
unsigned size() { return primes.size(); }
integer back() { return primes.back(); }
integer operator[](unsigned index) { return primes[index]; }
integer prime_factor(integer input) {
for (int i = 0; primes[i] * primes[i] <= input; i++)
if (input % primes[i] == 0)
return prime_factor(input / primes[i]);
return input;
}
};
int main() {
prime_table s(input);
integer current = 1;
clock_t start = clock();
for (int i = 0; i < s.size(); i++) {
if ((input % s[i]) == 0) {
if (s[i]>current)
current = s[i];
integer candidate = input / s[i];
candidate = s.prime_factor(candidate);
if (candidate > current) {
current = candidate;
if (current > s.back())
break;
}
}
}
clock_t stop = clock();
std::cout << "\n" << current << "\n";
std::cout << "Time: " << double(stop - start) / CLOCKS_PER_SEC << " seconds\n";
}
Unfortunately, this has the exact opposite problem most attempts do: rather than taking far too long to run, it runs so fast that much of the time it simply shows the minimum interval (1 millisecond) the clock
implementation I'm using can measure. Worse, a substantial part of the time, it shows up as running in 0 milliseconds.
To try to get a better idea of the speed, I chose a somewhat larger number to factor -- specifically I tacked 77
on the end to get of the input suggested by Project Euler to get 60085147514377
. The code above gives the largest prime factor as 345937 (which Wolfram Alpha agrees is the largest prime factor of this number) in about 9 or 10 milliseconds.
Specific question: implicit in almost any question like this is one of whether further improvements in speed can be achieved easily. I'm reasonably certain there is room for improvement in the sieving part.
I'm also somewhat uncertain about the number theory part--I think this is correct, and it produces correct results for every test I've tried, but I feel slightly less than 100% certain that there couldn't be some input for which it could produce an incorrect result.
1. I'm aware, for example, that the sieve of Atkins is at least theoretically faster than the sieve of Eratosthenes, but it apparently requires fairly non-trivial code to actually achieve that theoretical speedup so I haven't attempted to implement it here.