I have written a program to find prime numbers up to a given limit using wheel factorization of 2, 3 and 5. I would like it to work above \$10^{10}\$, but its still pretty slow.
- What else can I optimize here.
- Any way I can parallelize it?
- I am pretty sure
markNonPrimes
's algorithm is less efficient than it should be. Is it? I feel that I am brute forcing there: it takes ~250ms whenlimit
is \$10^6\$, ~1500ms whenlimit
is \$10^8\$.
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
typedef uint64_t u64;
const uint8_t ONE = 1;
const u64 F30[] = {1,7,11,13,17,19,23,29};
void markNonPrimes(const u64 start, const u64 num, const u64 lcm, const u64 limit, std::vector<uint8_t> &primes)
{
for (u64 k = start; (lcm*k) < limit; k++)
{
u64 K = lcm*k;
if ((primes[k] & (ONE << 0)) && (K+F30[0]) % num == 0)
primes[k] &= ~(ONE << 0);
if ((primes[k] & (ONE << 1)) && (K+F30[1]) % num == 0)
primes[k] &= ~(ONE << 1);
if ((primes[k] & (ONE << 2)) && (K+F30[2]) % num == 0)
primes[k] &= ~(ONE << 2);
if ((primes[k] & (ONE << 3)) && (K+F30[3]) % num == 0)
primes[k] &= ~(ONE << 3);
if ((primes[k] & (ONE << 4)) && (K+F30[4]) % num == 0)
primes[k] &= ~(ONE << 4);
if ((primes[k] & (ONE << 5)) && (K+F30[5]) % num == 0)
primes[k] &= ~(ONE << 5);
if ((primes[k] & (ONE << 6)) && (K+F30[6]) % num == 0)
primes[k] &= ~(ONE << 6);
if ((primes[k] & (ONE << 7)) && (K+F30[7]) % num == 0)
primes[k] &= ~(ONE << 7);
}
}
void getPrimesUpto(u64 limit)
{
const u64 lcm = 30;
std::vector<uint8_t> primes(limit*0.26 + 1,0xff);
u64 k = 1;
u64 n = 0;
u64 count=3-1;
markNonPrimes(k, F30[1], lcm, limit, primes);
markNonPrimes(k, F30[2], lcm, limit, primes);
markNonPrimes(k, F30[3], lcm, limit, primes);
markNonPrimes(k, F30[4], lcm, limit, primes);
markNonPrimes(k, F30[5], lcm, limit, primes);
markNonPrimes(k, F30[6], lcm, limit, primes);
markNonPrimes(k, F30[7], lcm, limit, primes);
while(lcm*k*lcm*k<limit)
{
const u64 K = lcm*k;
if(primes[k] & (ONE<<0))
markNonPrimes(k+1, K+F30[0], lcm, limit, primes);
if(primes[k] & (ONE<<1))
markNonPrimes(k+1, K+F30[1], lcm, limit, primes);
if(primes[k] & (ONE<<2))
markNonPrimes(k+1, K+F30[2], lcm, limit, primes);
if(primes[k] & (ONE<<3))
markNonPrimes(k+1, K+F30[3], lcm, limit, primes);
if(primes[k] & (ONE<<4))
markNonPrimes(k+1, K+F30[4], lcm, limit, primes);
if(primes[k] & (ONE<<5))
markNonPrimes(k+1, K+F30[5], lcm, limit, primes);
if(primes[k] & (ONE<<6))
markNonPrimes(k+1, K+F30[6], lcm, limit, primes);
if(primes[k] & (ONE<<7))
markNonPrimes(k+1, K+F30[7], lcm, limit, primes);
k++;
}
for(u64 k=0; lcm*k < limit; k++ )
{
for(u64 i =0; i<8; i++)
if(primes[k] & ONE<< i && lcm*k+F30[i] < limit) {count++;/*std::cout << lcm*k+F30[i] << " ";*/}
}
std::cout << "\n======\n"<< count << "\n";
}
int main()
{
clock_t start = clock();
getPrimesUpto(100);
std::cout << "\nTime: "<< clock() - start << std::endl;
}