I must say, the naming of variables and the code structure as posted in the question, with the double while
instead of an if
, is very non-conducive to the code clarity.
Consequently, I'd re-structure your code as
int main(){
vector<int> primes; // primes known so far
vector<int> mults; // smallest multiple of each prime, above c
int c = 1; // candidates: 2,3,...
bool composite;
while (true) {
composite = false;
c++; // 2,3,...
for (int i = 0; i < (int)primes.size(); i++) {
if (c == mults[i]) { // if c is a multiple of ith prime,
composite = true; // then it's composite.
mults[i] += primes[i]; // next multiple of this prime
}
}
if( !composite ) {
mults.push_back(c*2); // first multiple of
primes.push_back(c); // newly found prime
}
}
}
Now we can see, first of all, a major algorithmic deficiency in your code: the wrong "data structure" you use to maintain the primes' multiples. Instead of min-heap priority queue which would immediately produce the next known multiple of a prime, you maintain two linear vectors and scan through them for each candidate number. This is bound to have major implications, complexity-wise. And with worse complexity no amount of constant factors improvements will help much.
But putting this aside, on to your question. You enumerate the multiples of each prime p
as 2p, 3p, 4p, ...
.
First step is to switch it to p², p²+p, p²+2p, ...
.
Next, we notice that for all odd primes, p²
is odd as well and so the enumeration can be changed to p², p²+2p, p²+4p, ...
, to enumerate all odd multiples of it.
And what to do with the even ones? How to test for them now? The whole point to this "wheel factorization" optimization is to not do any such tests, but just ignore them. That's why it's an optimization in the first place.
And the way to ignore them is to not generate any even candidates, in the first place -- because we known in advance that all of them aren't primes any way. And that is the essence of the wheel optimization:
int main(){
vector<int> primes; // primes known so far
vector<int> mults; // smallest multiple of each prime, above c
int c = 1; // candidates: 3,5,...
bool composite;
while (true) {
composite = false;
c+=2; // 3,5,...
for (int i = 0; i < (int)primes.size(); i++) {
if (c == mults[i]) { // if c is a multiple of ith prime,
composite = true; // then it's composite
mults[i] += 2*primes[i]; // next multiple of this prime
}
}
if( !composite ) {
mults.push_back(c*c); // first multiple of
primes.push_back(c); // newly found prime
}
}
}
Next, switching to your desired mod 6 +-1
enumeration, we will ignore the multiples of 2 and 3. But then it means, we'll need to not generate any of them as well. The enumeration of multiples will be m=p²; m+=4; m+=2; m+=4; m+=2; m+=4; m+=2; ...
for some, and m=p²; m+=2; m+=4; m+=2; m+=4; m+=2; m+=4; ...
for others (you can figure out the details).
And the enumeration of the candidates will just start from 5, and also proceed as c=5; c+=2; c+=4; c+=2; c+=4; c+=2; c+=4; ...
.
Hopefully you can write this down now in an actual code.
P.S. you can find more details in several of my answers on the matter, e.g. here and here etc..