Implementing Sieve of Eratosthenes

Jul 26, 2012 at 6:13pm
So, I've been project euler problems lately, and hit one that asks for the 10,001st prime number. After some research, it seems as if a sieve is the way to go. Though, I'm not sure how to implement it. I was originally thinking of making a struct to hold a hold a number, and a bool saying whether it's composite or not. Though this would require making probably 100k plus objects of this, and that definitely seems pretty slow and sloppy. Any suggestions?
Jul 26, 2012 at 8:32pm
Couldent you just calculate all the prime numbers up to 10001st prime number using the modulus operator and submit that? Or dose your problem explicity ask for ONLY the 10001st prime number?
Jul 26, 2012 at 11:38pm
I can understand that you might want to implement the Sieve method for the sake of it, but for this problem it certainly isn't necessary.

I suggest:

iterate through numbers

    if the number is prime (check using a function), increase the count of primes

        if the number of primes is 10001, output the current number

Jul 27, 2012 at 1:55am
I solved this problem a long time ago, and what I remember I did was to use an array of booleans, and to apply the algorithm of the sieve and set a position to true if it was a prime. It ran pretty fast, and I remember the runtime was less than a second... and that's saying something, considering I wrote it in Java.
Jul 27, 2012 at 2:52am
Is the sieve method really that fast? Wow, I seem to remember my method taking a few seconds and I thought that was fairly good...
Jul 27, 2012 at 2:56am
Here's a picture (.gif) of what the sieve is doing:
http://upload.wikimedia.org/wikipedia/commons/b/b9/Sieve_of_Eratosthenes_animation.gif

Never done this myself. Seems like you make a bool array (much larger than 10001), and set everything to true. Then consider the index in the array to be the number you are checking:

I don't know if you're reading this, but I've learned as I posted.

Make yourself a very large bool array and set all of the values to true. The integer you deal with is the index in the array. [0] and [1] don't count, our first prime is [2].

2 is prime, which means that 4,6,8... is not prime, so go through the array setting every multiple of 2 to false. Then increase your counter to 3, look at if it is true. Since it is, every index that is a multiple of three is false. Then go through looking for true, so skip over 4 and find 5.... Repeat

It's proven that when you increase your index looking for "true", the index you find is a prime number. There is no math type math going on.
Last edited on Jul 27, 2012 at 3:16am
Jul 27, 2012 at 1:25pm
It just seems like creating a massive array is a little silly. And having basically parallel arrays like a couple of you described seems to be the exact same as my vector of struct idea.

Either one seems sloppy to me, but I can't see a better to do it.

And thanks for the link LowestOne, though I have already seen it. Wikipedia is actually the only place I've looked at this algorithm at lol
Jul 27, 2012 at 9:41pm
No need for parallel arrays.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <fstream>
int main()
{
	const int max = 1000000;
	int count = 1;
	bool arr[max];

	for(int i = 0; i < max; ++i)
		arr[i] = true;

	for(int i = 2; i < max-1; )
	{
		if(count == 10001)
		{
			std::cout<<i;
			break;
		}
		//mark all multiples
		for(int j = 2; (j*i) < max-1; ++j)
		{
			arr[i*j] = false;
		}
		//find next prime
		for(int k = i+1; k < max-1; k++)
		{
			if(arr[k])
			{				
				i=k;
				++count;
				break;
			}	
		}
	}

	return EXIT_SUCCESS;
}
Jul 28, 2012 at 2:55am
If you don't want to use an array:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>

typedef unsigned int uInt;

int main()
{
	bool is_prime;

	uInt count = 1;
	uInt my_prime = 2; //set to first prime

	for(uInt i = 3; count < 10001; i += 2) { //skip ALL even numbers, find 10001st prime

		is_prime = true;

		for(uInt j = 3; j * j <= i && is_prime; j += 2) //again, skipping all even numbers
			if(i % j == 0) is_prime = false;

		if(is_prime) {
			++count;
			my_prime = i;
		}
	}

	std::cout << my_prime;
	std::cin.get();
}
Jul 28, 2012 at 6:52am
two prime number programs
http://cplusplus.shinigami.lt/page/2/
Jul 28, 2012 at 7:47am
> It just seems like creating a massive array is a little silly

A sieve is an array.

The sieve of Sundaram cuts down the size of the sieve by two.
Using a bit for each element reduces memory usage.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <vector>
#include <boost/dynamic_bitset.hpp>
#include <cmath>
#include <limits>
#include <cmath>
#include <iostream>

boost::dynamic_bitset<> sieve_of_sundaram( std::size_t N )
{
    const std::size_t M = N / 2 ;
    boost::dynamic_bitset<> sieve(M) ;
    sieve.flip() ;

    for( std::size_t i = 1 ; i < M ; ++i )
    {
        const std::size_t L = (M-i) / ( 2*i + 1 ) ;
        for( std::size_t j = i ; j <= L ; ++j ) sieve[ i + j + 2*i*j ] = false ;
    }

    return sieve ;
}

std::vector<int> prime_number_sequence( std::size_t lbound, std::size_t ubound )
{
    auto sieve = sieve_of_sundaram(ubound) ;
    std::vector<int> primes ;
    if( lbound < 3 ) { primes.push_back(2) ; lbound = 3 ; }

    for( std::size_t i = (lbound-1)/2 ; i < sieve.size() ; ++i )
        if( sieve[i] ) primes.push_back( i*2 + 1 ) ;

    return primes ;
}

int nth_prime_number( std::size_t n )
{
    int number = 2 ;
    if( n > 1 )
    {
        // the nth prime number is approximately equal to n * log(n)
        double ubound = std::max( 100.0, n * std::log(n) * 1.5 ) ;
        assert( ubound < std::numeric_limits<std::size_t>::max() ) ;
        auto sieve = sieve_of_sundaram(ubound) ;
        std::size_t pos = 1 ;
        for( std::size_t i = pos ; n > 1 ; ++i ) if( sieve[i] ) { pos = i ; --n ; }
        assert( pos < std::numeric_limits<int>::max() / 2 ) ;
        number = pos * 2 + 1 ;
    }

    return number ;
}

int main()
{
    for( int n : prime_number_sequence( 7000, 7100 ) ) std::cout << n << ' ' ;
    std::cout << '\n' ;

    for( std::size_t n = 100 ; n < 1000000 ; n *= 10 )
         std::cout << n+1 << ": " << nth_prime_number(n+1) << '\n' ;
}

Output:
7001 7013 7019 7027 7039 7043 7057 7069 7079
101: 547
1001: 7927
10001: 104743
100001: 1299721

Last edited on Jul 28, 2012 at 8:00am
Jul 28, 2012 at 10:43am
I'll let you guess what language this is, RB:
1
2
3
   p: 10000
104743
   

Jul 28, 2012 at 1:27pm
J?
Topic archived. No new replies allowed.