I've been working on a little problem where I need to compute 18-digit numbers into their respective prime factorization. Everything compiles and it runs just fine, considering that it actually works, but I am looking to reduce the run time of the prime factorization. I have implemented recursion and threading but I think I might need some help in understanding possible algorithms for large number computation.
Every time I run this on the 4 numbers I have pre-made, it takes about 10 seconds. I would like to reduce this to possibly 0.06 seconds if there are any ideas out there.
I noticed a few algorithms like Sieve of Eratosthenes and producing a list of all the prime numbers prior to computing. I'm just wondering if someone could elaborate on it. For instance, I'm having issues understanding how to implement Sieve of Eratosthenes into my program or if it would even be a good idea. Any and all pointers on how to approach this better would be really helpful!
Here is my code:
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
using namespace std;
using namespace std::chrono;
vector<thread> threads;
vector<long long> inputVector;
bool developer = false;
vector<unsigned long long> factor_base;
vector<long long> primeVector;
class PrimeNumber
{
long long initValue; // the number being prime factored
vector<long long> factors; // all of the factor values
public:
void setInitValue(long long n)
{
initValue = n;
}
void addToVector(long long m)
{
factors.push_back(m);
}
void setVector(vector<long long> m)
{
factors = m;
}
long long getInitValue()
{
return initValue;
}
vector<long long> getVector()
{
return factors;
}
};
vector<PrimeNumber> primes;
// find primes recursively and have them returned in vectors
vector<long long> getPrimes(long long n, vector<long long> vec)
{
double sqrt_of_n = sqrt(n);
for (int i = 2; i <= sqrt_of_n; i++)
{
if (n % i == 0)
{
return vec.push_back(i), getPrimes(n / i, vec); //cause recursion
}
}
// pick up the last prime factorization number
vec.push_back(n);
//return the finished vector
return vec;
}
void getUserInput()
{
long long input = -1;
cout << "Enter all of the numbers to find their prime factors. Enter 0 to compute" << endl;
do
{
cin >> input;
if (input == 0)
{
break;
}
inputVector.push_back(input);
} while (input != 0);
}
int main()
{
vector<long long> temp1; // empty vector
vector<long long> result1; // temp vector
if (developer == false)
{
getUserInput();
}
else
{
cout << "developer mode active" << endl;
long long a1 = 771895004973090566;
long long b1 = 788380500764597944;
long long a2 = 100020000004324000;
long long b2 = 200023423420000000;
inputVector.push_back(a1);
inputVector.push_back(b2);
inputVector.push_back(b1);
inputVector.push_back(a2);
}
high_resolution_clock::time_point time1 = high_resolution_clock::now();
// give each thread a number to comput within the recursive function
for (int i = 0; i < inputVector.size(); i++)
{
PrimeNumber prime;
prime.setInitValue(inputVector.at(i));
threads.push_back(thread([&]{
prime.setVector(result1 = getPrimes(inputVector.at(i), temp1));
primes.push_back(prime);
}));
}
// allow all of the threads to join back together.
for (auto& th : threads)
{
cout << th.get_id() << endl;
th.join();
}
high_resolution_clock::time_point time2 = high_resolution_clock::now();
// print all of the information
for (int i = 0; i < primes.size(); i++)
{
vector<long long> temp = primes.at(i).getVector();
for (int m = 0; m < temp.size(); m++)
{
cout << temp.at(m) << " ";
}
cout << endl;
}
cout << endl;
// so the running time
auto duration = duration_cast<microseconds>(time2 - time1).count();
cout << "Duration: " << (duration / 1000000.0) << endl;
return 0;
}
i
is a factor ofn
, then no number smaller thani
is a factor ofn/i
either, and there's no need checking all of those again. In particular, ifi
is the smallest factor ofn
andi
is greater than the cube root ofn
, theni
andn/i
are the only factors ofn
. It's not necessary to do that specific check, though; it will be automatic if you start the next search ati
. – Chenaya1 = 771895004973090566
, can be factored in less than 1/2000 second (or better), because it is 2 x 385947502486545283. The factor 2 is of course found instantly. Then, 385947502486545283 is easily determined to be prime using Miller–Rabin. Similarly,a2 = 788380500764597944
can be factored almost instantly to 2 x 2 x 2 x 7 x 14078223227939249. The challenge is actually to factor hard semiprimes like 18436839306515468081 = 2988873347 x 6168491323, and for that you want Shanks's Square Forms Factorization, Hart's One-Line Factorization, or Brent–Pollard Rho. – Michey