Algorithm for largest prime factor

Jakotheshadows

New member
Joined
Jun 29, 2008
Messages
47
I'm working on Project Euler problem 3: http://projecteuler.net/index.php?section=problems&id=3.

I have some code done and I think it will eventually compute a valid answer for me. However, the spirit of these Project Euler problems is that they are computable by a reasonably powered computer in a minute or less. I've given the algorithm that I have 5 solid minutes to compute this, and it isn't finished. For the C++ inclined, here is my complete code:
Code:
#include <iostream>
#include <cmath>
#include <set>
#include <cassert>
#include <fstream>
using namespace std;

template <typename T>
void intFiller(set<T>& p, unsigned long long largest);
template <typename T>
void primeFinder(set<T>& p, unsigned long long largest);
template <typename T>
void primeFactor(set<T>& p, unsigned long long biggest);
template <typename T>
ostream& operator<<(ostream& o, set<T> p);

int main()
{
	unsigned long long n;
	ofstream projTxt;
	set<unsigned long long> primes;

	projTxt.open("project3.txt");
	cout << "Please specify largest possible prime: ";
	projTxt << "Please specify largest possible prime: ";
	cin >> n;
	projTxt << n << endl;

	intFiller(primes, n);
	//Now primes is the set of positive integers on the interval [2,n]
	primeFinder(primes, n);
	//Now primes is the set of all prime numbers in the interval [2,n)

	cout << primes;
	cout << endl;
	cout << "and the prime factors of " << n << " are: \n";
	primeFactor(primes, n);
	cout << primes;

	if(projTxt.is_open())
    projTxt << primes;

	projTxt.close();
}

template <typename T>
void primeFactor(set<T>& p, unsigned long long biggest)
{
	set<T>::iterator iterP = p.begin();
	unsigned long long factor;

	while(iterP!=p.end())
	{
		factor = *iterP;
		if((biggest%factor)!=0)
		{
			p.erase(factor);
			iterP = p.begin();
		}
		else
			++iterP;
	};
}


template <typename T>
void intFiller(set<T>& p, unsigned long long largest)
{
	unsigned long long i;

	for(i=2; i<=largest; ++i)
	{
		p.insert(i);
	};
}

template <typename T>
void primeFinder(set<T>& p, unsigned long long largest)
{
	set<T>::iterator iterP = p.begin();
	unsigned long long i, k;

	while(iterP!=p.end())
	{
		for(i=2; i<=sqrt(double(largest)); ++i)
		{
			for(k=2; (i*k)<=largest; ++k)
			{
				iterP = p.find(i*k);
				if(iterP!=p.end())
					p.erase(iterP);
			};
		};
	};
}

template<typename T>
ostream& operator<<(ostream& out, set<T> p)
{
	set<T>::iterator output;

	if(!p.empty())
	{
		for(output=p.begin(); output!=p.end(); ++output)
		{
			out << *output;
			out << endl;
		};
	};

	return out;
}
[/spoiler:3kxcrom4]

Basically this code does the following:
1. Uses the Sieve of Eratosthenes to compute primes less than or equal to a given number.
2. Checks to see which of those primes does not evenly divide the given number, and strikes them out.

My code works over a fair range of numbers, but something like 600851475143 will just take ages. I feel like I need to seek mathematical advice on this and learn up a little more on prime numbers. I notice that the sieve of eratosthenes just keeps going until you get to multiples of numbers greater than the given number's square root. Is there some particular reason for this? Is there some way I can exploit this to take any sort of significant shortcut to finding the largest prime factor of a number?
 
Jakotheshadows said:
I'm working on Project Euler problem 3: http://projecteuler.net/index.php?section=problems&id=3.

I have some code done and I think it will eventually compute a valid answer for me. However, the spirit of these Project Euler problems is that they are computable by a reasonably powered computer in a minute or less. I've given the algorithm that I have 5 solid minutes to compute this, and it isn't finished. For the C++ inclined, here is my complete code:
Code:
#include <iostream>
#include <cmath>
#include <set>
#include <cassert>
#include <fstream>
using namespace std;

template <typename T>
void intFiller(set<T>& p, unsigned long long largest);
template <typename T>
void primeFinder(set<T>& p, unsigned long long largest);
template <typename T>
void primeFactor(set<T>& p, unsigned long long biggest);
template <typename T>
ostream& operator<<(ostream& o, set<T> p);

int main()
{
	unsigned long long n;
	ofstream projTxt;
	set<unsigned long long> primes;

	projTxt.open("project3.txt");
	cout << "Please specify largest possible prime: ";
	projTxt << "Please specify largest possible prime: ";
	cin >> n;
	projTxt << n << endl;

	intFiller(primes, n);
	//Now primes is the set of positive integers on the interval [2,n]
	primeFinder(primes, n);
	//Now primes is the set of all prime numbers in the interval [2,n)

	cout << primes;
	cout << endl;
	cout << "and the prime factors of " << n << " are: \n";
	primeFactor(primes, n);
	cout << primes;

	if(projTxt.is_open())
    projTxt << primes;

	projTxt.close();
}

template <typename T>
void primeFactor(set<T>& p, unsigned long long biggest)
{
	set<T>::iterator iterP = p.begin();
	unsigned long long factor;

	while(iterP!=p.end())
	{
		factor = *iterP;
		if((biggest%factor)!=0)
		{
			p.erase(factor);
			iterP = p.begin();
		}
		else
			++iterP;
	};
}


template <typename T>
void intFiller(set<T>& p, unsigned long long largest)
{
	unsigned long long i;

	for(i=2; i<=largest; ++i)
	{
		p.insert(i);
	};
}

template <typename T>
void primeFinder(set<T>& p, unsigned long long largest)
{
	set<T>::iterator iterP = p.begin();
	unsigned long long i, k;

	while(iterP!=p.end())
	{
		for(i=2; i<=sqrt(double(largest)); ++i)
		{
			for(k=2; (i*k)<=largest; ++k)
			{
				iterP = p.find(i*k);
				if(iterP!=p.end())
					p.erase(iterP);
			};
		};
	};
}

template<typename T>
ostream& operator<<(ostream& out, set<T> p)
{
	set<T>::iterator output;

	if(!p.empty())
	{
		for(output=p.begin(); output!=p.end(); ++output)
		{
			out << *output;
			out << endl;
		};
	};

	return out;
}
[/spoiler:utay00vk]

Basically this code does the following:
1. Uses the Sieve of Eratosthenes to compute primes less than or equal to a given number.
2. Checks to see which of those primes does not evenly divide the given number, and strikes them out.

My code works over a fair range of numbers, but something like 600851475143 will just take ages. I feel like I need to seek mathematical advice on this and learn up a little more on prime numbers. I notice that the sieve of eratosthenes just keeps going until you get to multiples of numbers greater than the given number's square root. Is there some particular reason for this? Is there some way I can exploit this to take any sort of significant shortcut to finding the largest prime factor of a number?
A "non-square" number is factored as follows

number = (another number less than the square root) * (another number more than the square root)

for example:

for example I need to check for factors of 60. \(\displaystyle \sqrt{60} \ ~8\). then we have:

60 = 2 * 30

60 = 3 * 20

60 = 4 * 15

60 = 5 * 12

60 = 6 * 10

the next divisor of 60 is 10 - but I don't need to check it, because I have it in my list of divisors already from the 5 th equation (or calculation).

And, the next divisor of 60 is 12 - but I don't need to check it, because I have it in my list of divisors already from the 4 th equation (or calculation).

And so on....

So I needed to check only one factor above 8 (the approximate square root) - to get all the factors.

Ofcourse when you are looking for prime factors (of 60), you'll divide by 2, 2, 3, 5 - you have the original number and you don't need to go any further.
 
Thanks for your reply Subhotosh Khan. I'm still noticing that the sieve of eratosthenes itself (commenting out part 2 of my algorithm) is taking entirely too long to compute all of the primes up to numbers in the hundred billions. I'm thinking I might have to skip the sieve altogether to get this computed in a reasonable amount of time. Is there some other bit of mathematical logic I can use to cut right to the chase in computing a largest prime factor? I read somewhere that the smallest factor of a number will always be prime. Is this true?
 
No it doesn't help me. I read it already and its preceding post, but the problem is that I don't really understand what he's saying and I can't read his perl code since I've never touched perl before. In fact, his preceding post is where I read that the smallest factor of a number is always prime. Can anyone else here confirm that? I'm also puzzled by what he is doing I don't understand if or why it works.
 
Jakotheshadows said:
No it doesn't help me. I read it already and its preceding post, but the problem is that I don't really understand what he's saying and I can't read his perl code since I've never touched perl before. In fact, his preceding post is where I read that the smallest factor of a number is always prime. Can anyone else here confirm that? I'm also puzzled by what he is doing I don't understand if or why it works.

Has to be! If the smallest factor is a composite number - it is made of at least two smaller prime number - which would then be smaller facter of the original number.

Did you try 6n + 1 and 6n -1 as your factors yet?

n= 1 ? 5, 7
n=2? 11, 13

and so on...
 
Subhotosh Khan said:
Jakotheshadows said:
No it doesn't help me. I read it already and its preceding post, but the problem is that I don't really understand what he's saying and I can't read his perl code since I've never touched perl before. In fact, his preceding post is where I read that the smallest factor of a number is always prime. Can anyone else here confirm that? I'm also puzzled by what he is doing I don't understand if or why it works.

Has to be! If the smallest factor is a composite number - it is made of at least two smaller prime number - which would then be smaller facter of the original number.

Did you try 6n + 1 and 6n -1 as your factors yet?

n= 1 ? 5, 7
n=2? 11, 13

and so on...

Will 6n+1 and 6n-1 always be prime? I could try that relatively easily if that is the case.
 
Ok so I just read up on that idea that primes past 2 and 3 have the form 6n+-1, so I'm thinking I might have something here.
1. Loop through values of 6n+1 < square root of given number, store the final value before the loop terminates.
2. Loop through values of 6n-1 < square root of given number, store the final value before the loop terminates.
3. Test to see if result 1 is prime, if it isn't result 2 is prime. If the chosen prime result evenly divides the given number it is the largest prime factor.

Would this work?
 
Jakotheshadows said:
Ok so I just read up on that idea that primes past 2 and 3 have the form 6n+-1, so I'm thinking I might have something here.
1. Loop through values of 6n+1 < square root of given number, store the final value before the loop terminates.
2. Loop through values of 6n-1 < square root of given number, store the final value before the loop terminates.
3. Test to see if result 1 is prime, if it isn't result 2 is prime. If the chosen prime result evenly divides the given number it is the largest prime factor.

Would this work?

Remember all the 6n + 1 numbers are not - e.g. - 6*4 + 1
 
Subhotosh Khan said:
Jakotheshadows said:
Ok so I just read up on that idea that primes past 2 and 3 have the form 6n+-1, so I'm thinking I might have something here.
1. Loop through values of 6n+1 < square root of given number, store the final value before the loop terminates.
2. Loop through values of 6n-1 < square root of given number, store the final value before the loop terminates.
3. Test to see if result 1 is prime, if it isn't result 2 is prime. If the chosen prime result evenly divides the given number it is the largest prime factor.

Would this work?

Remember all the 6n + 1 numbers are not - e.g. - 6*4 + 1

So just use 6n-1 then?

It seem that some of the 6n+1 numbers would be. Like 6*3+1=19? Also the 6*3-1=17. Wouldn't it be prudent in that case just to have both of those loops so that other primes don't slip through?
 
All 6n - 1 are not prime either - e.g. - 6*6 - 1.

Understand the logic behind the logic of the loop - instead of just following it.
 
Subhotosh Khan said:
All 6n - 1 are not prime either - e.g. - 6*6 - 1.

Understand the logic behind the logic of the loop - instead of just following it.

Ok, well for any given n then, is it true that either 6n-1 or 6n+1 is prime? (Not exclusive or)
If so, my logic is that I will eventually get some 6n+1 and some 6n-1 that is just a bit less than the square root of my given number. One of those should be prime, and hopefully one of them evenly divides my given number. Also I should add that in each loop iteration I make sure the number evenly divides the given number before bothering to store it.
 
Jakotheshadows said:
Subhotosh Khan said:
All 6n - 1 are not prime either - e.g. - 6*6 - 1.

Understand the logic behind the logic of the loop - instead of just following it.

Ok, well for any given n then, is it true that either 6n-1 or 6n+1 is prime? (Not exclusive or)
If so, my logic is that I will eventually get some 6n+1 and some 6n-1 that is just a bit less than the square root of my given number. One of those should be prime, and hopefully one of them evenly divides my given number. Also I should add that in each loop iteration I make sure the number evenly divides the given number before bothering to store it.

There is NO known "easy" formula for computing prime numbers, nor testing to see if a number is prime. Finding big prime numbers is a very hard problem. If what you said was true, it wouldn't be.
 
Well, I solved the problem. I just used a trial and error algorithm that required several attempts. Instead of computing ALL primes less than that god-awful huge number, I just re-ran the program and doubled the number of primes computed each time and then used prime factorization. I'm glad I didn't sell my discrete math textbook. Thanks for the help anyways guys.
 
Top