I have a programming assignment to write a program in C++ that finds all primes less than n (user input). One half of the assignment involves the Sieve of Eratosthenes. My code is working (read: assignment is complete), but before I edited the output, it was unconditionally printing out n-3, n-2, and n-1 as primes even if they were not prime. I’m not sure why this is happening. I’d appreciate a bit of feedback and ideas as to why the program is acting the way it is. Here is the unaltered code:
Please note that I am using a ListNode class and a LinkedList class, both of which are fully functional. EDIT: partial main added; notice the second item in the for loop is size-3. If it’s left at size, the program outputs 3 extra non-primes.
int main()
{
for(int i = 0; i<my_list.size()-3; i++)
{
if(marked[i]==true)
cout<<my_list[i]<<"\n";
}
}
void eratosthenes(int item)
{
bool run=true;
int p=2, count=0;
for(int i=2; i<=item; i++)
{
my_list.append(i); // Entire list is filled with integers from 2 to n
marked.append(true); // Entire list is filled with true entries
}
while(run==true&&(2*p)<item)
{
count = 0;
int i = (2*p);
do {
marked[i-2]=false; // marked values are false and not prime
i+=p;
} while(i<item-2);
for(int i=0; i<item-2; i++) // i starts at 0 and increments by 1
{ // each time through the loop
if(my_list[i]>p)
{
if(marked[i]==true) // If a value stored in a node is true
{ // (prime), it becomes the new p.
p=my_list[i]; // The loop is then broken.
break;
}
}
}
for(int j=1; j<item-2; j++)
{
if(marked[j]==false)
{
count=1;
}
}
if(count==0)
run=false;
}
From your code:
This loop is responsible for going through all numbers
ithat are integer multiples of the prime numberpand marking them not prime, as I understand. Why are you stopping on the conditioni < item - 2? This would be fine ifiwere your index for themy_listandmarkedlists, but in this case it’s not; it’s the actual number you’re marking not prime. I suspect this is why you’re getting numbers near your limit (item) that are marked as prime—your loop here exits beforeiever gets to those numbers!By the way, you could do this as a for loop instead, which would be easier to read. The for loop has the meaning “go through each element in a set” (whether that’s consecutive integers, or every nth integer, or elements in an array/list/deque, etc.), so a programmer reading your code knows that immediately and doesn’t have to figure it out from your while loop.
(This is the same as your original code, no fixes applied).
Some general comments to improve your algorithm/code:
Try using more descriptive variable names. Your use of
itwo times to mean different things is confusing, and in general single letters don’t mean much as to what the variable represents (although sometimes they’re sufficient, e.g. a for loop whereiis the index of a list/array).Also, you’re looping over your list a lot more than you need to. The minimum a sieve of Eratosthenes algorithm needs is two nested for loops (not including initializing a list/array to all
true).One example of where you’re doing more work than necessary is that you’re looping starting from index 0 to find the next
pto use—instead of just remembering where your currentpis and starting from there. You wouldn’t even need to checkmy_list[i] > pin that case, since you know you’d be beyond it to start off. Also, your last loop couldbreak;early and avoid continuing on after it finds a non-prime (and I’m not sure what the point of it is).Nikola Mitev’s second answer is a more efficient and more readable implementation of the sieve (
but replace), although he didn’t really give much comment or explanation on it. The first loop is “go through every number up to upperBound”; inside it, “if the current number is a prime, go through all the multiples of that prime and mark them non-prime”. After that innerloop executes, the outer loop continues, going through the next numbers—no need to start from the beginning, or even type out another for loop, to find the next prime.sqrt(upperBound)withupperBound/2for it to work correctly; the reason forupperBound/2should be pretty clear from the way the Sieve worksEDIT:
sqrt(upperBound)is correct. I wasn’t thinking about it carefully enough.