I attempted Project Euler’s problem 10 using the very easy algorithm and the running time looks like hours. So I googled for an efficient algorithm and found this by Shlomif Fish.
The code is reproduced below:
int main(int argc, char * argv[])
{
int p, i;
int mark_limit;
long long sum = 0;
memset(bitmask, '\0', sizeof(bitmask));
mark_limit = (int)sqrt(limit);
for (p=2 ; p <= mark_limit ; p++)
{
if (! ( bitmask[p>>3]&(1 << (p&(8-1))) ) )
{
/* It is a prime. */
sum += p;
for (i=p*p;i<=limit;i+=p)
{
bitmask[i>>3] |= (1 << (i&(8-1)));
}
}
}
for (; p <= limit; p++)
{
if (! ( bitmask[p>>3]&(1 << (p&(8-1))) ) )
{
sum += p;
}
}
I have problems understanding the code. Specifically, how does this bit shifting code able to determine whether a number is prime or not.
if (! ( bitmask[p>>3]&(1 << (p&(8-1))) ) )
{
/* It is a prime. */
sum += p;
for (i=p*p;i<=limit;i+=p)
{
bitmask[i>>3] |= (1 << (i&(8-1)));
}
}
Can someone please explain this code block to me, especially this part ( bitmask[p>>3]&(1 << (p&(8-1)? Thank you very much.
The code is a modified Sieve of Eratosthenes. He is packing one number into one bit:
0= prime,1= composite. The bit shifting is to get to the correct bit in the byte array.is equivalent to
which selects the correct byte in the
bitmask[]array.equals
p & 7, which selects the lower 3 bits ofp. This is equivalent top % 8Overall we are selecting bit
(p % 8)of bytebitmask[p / 8]. That is we are selecting the bit in thebitmask[]array which represents the number p.The
1 << (p % 8)sets up a1bit correctly located in a byte. This is then AND’ed with thebitmask[p / 8]byte to see if that particular bit is set or not, thus checking whetherpis a prime number.The overall statement equates to
if (isPrime(p)), using the already completed part of the sieve to help extend the sieve.