Largest prime factor
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
http://projecteuler.net/problem=3
The Easy Way
$ factor 600851475143
# 600851475143: 71 839 1471 6857
GNU coreutils
has a factor
command. If you are using a linux machine it is most likely already installed. On Mac’s you can install coreutils
using a package manager like homebrew
.
Brute Force
First lets make a Primes object that can generate an array of primes up to $n$. A prime number is any number that is only divisible by 1 and and itself. For a truly naive approach, to check if $n$ is prime, you would check every number in the range of $[2, n)$.
For our naive approach, we will keep an array of primes we have found and check if $n$ is divisible by any prime. We can do this because any non-prime number that $n$ is divisible by, is itself divisible by a previously found prime, making $n$ also divisible by that prime. We will also limit our search to odd numbers.
var NaivePrimes = (function() {
// Returns if n is prime using trial division for previously found primes.
function isPrime(n, primes) {
var pi = 1, // Skip checking if divisible by 2.
prime = primes[pi];
while (prime < n) {
if (!(n % primes[pi])) return false;
prime = primes[++pi]
}
return true;
}
function primesTo(n) {
var primes, i;
if (n < 2) return [];
if (n === 2) return [2];
if (n === 3) return [3];
primes = [2, 3];
i = 5;
while (i <= n) {
if (isPrime(i, primes)) primes.push(i);
i+=2;
}
return primes;
}
return {
primesTo : primesTo
}
})();
timer(NaivePrimes.primesTo, 1, 100000);
// primesTo x 1: 462.319ms
// Array[9592]
// [ 2,
// 3,
// 5,
// 7,
// ...
// 99971,
// 99989,
// 99991 ]
More Optimizations
The big optimization we can make is only checking if $n$ is divisible by numbers $\le \sqrt n$. This is because if $pq=n$ for $p$ and $q\neq 1$ and $\neq \sqrt n$, then $p$ or $q$ must be $\le \sqrt n$. If both $p$ and $q \gt \sqrt n$ it would contradict $\sqrt n \times \sqrt n = n$.
var LessNaivePrimes = (function() {
// Returns if n is prime using trial division for previously found primes.
// Only check up to floor(sqrt(n)).
function isPrime(n, primes) {
var pi = 1, // Skip checking if divisible by 2.
prime = primes[pi],
limit = Math.floor(Math.sqrt(n));
while (prime <= limit) {
if (!(n % prime)) return false;
prime = primes[++pi];
}
return true;
}
function primesTo(n) {
var primes, i;
if (n < 2) return [];
if (n === 2) return [2];
if (n === 3) return [3];
primes = [2, 3];
i = 5;
while (i <= n) {
if (isPrime(i, primes)) primes.push(i);
i+=2;
}
return primes;
}
return {
primesTo : primesTo
}
})();
timer(LessNaivePrimes.primesTo, 1, 100000);
// primesTo x 1: 34.117ms
// Array[9592]
Another optimization that we can make that reduces the number of $n$’s we need to check is all primes past $3$ can be generalized in the form $6i \pm 1$.
The proof for this generalization can be stated as:
Given a number, $n \gt 3$, dividing $n$ by $6$ gives you:
$n = 6x + r$ ; $x$ is a non-negative integer and $r$ is the remainder
for $r$ is $0$, $2$, or $4$ ; $n$ is divisible by $2$
for $r$ is $3$ ; $n$ is divisible by $3$
for $r$ is $1$ ; $n$ is $1$ more than a multiple of $6$
for $r$ is $5$ ; $n$ is $1$ less than a multiple of $6$
That means for all $n$ not in for form of $6i \pm 1$, $n$ is divisible by $2$ or $3$. This means we can eliminate all those from our checks.
Primes!
var Primes = (function() {
// Returns if n is prime using trial division for previously found primes.
// Only check up to floor(sqrt(n)).
function isPrime(n, primes) {
var pi = 1, // Skip checking if divisible by 2.
prime = primes[pi],
limit = Math.floor(Math.sqrt(n));
while (prime <= limit) {
if (!(n % prime)) return false;
prime = primes[++pi];
}
return true;
}
function primesTo(n) {
var primes, i = 1;
if (n < 2) return [];
if (n === 2) return [2];
if (n === 3) return [2, 3];
primes = [2, 3];
while (true) {
var candidate = 6 * i - 1;
if (candidate > n) break;
if (isPrime(candidate, primes)) primes.push(candidate);
candidate += 2;
if (candidate > n) break;
if (isPrime(candidate, primes)) primes.push(candidate);
i++;
}
return primes
}
return {
primesTo : primesTo
}
})();
timer(Primes.primesTo, 1, 100000);
// primesTo x 1: 26.513ms
// Array[9592]
Using the Prime Generator
To find the prime factors for our number, we can apply the same logic we did for checking primes for divisibility by only checking up to $\sqrt n$.
function euler3() {
var factors = [],
n = 600851475143,
limit = Math.floor(Math.sqrt(n)),
primes = Primes.primesTo(limit),
i = primes.length;
while (i--) {
if (n % primes[i] === 0) factors.push(primes[i]);
}
return factors;
}
timer(euler3);
// euler3 x 1: 243.233ms
// [6857, 1471, 839, 71]