Created
March 12, 2012 06:26
-
-
Save hjr3/2020292 to your computer and use it in GitHub Desktop.
Find all prime numbers in a given range using Sieve of Eratosthenes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// gcc -std=c99 -Wall -Werror -g -o primes primes.c -lm | |
#include <stdio.h> | |
#include <string.h> | |
#include <limits.h> | |
#include <math.h> | |
void primes(int length) | |
{ | |
unsigned int bits_per_int = (sizeof(unsigned int) * CHAR_BIT); | |
unsigned int mask_size = 0; | |
for (unsigned int x = bits_per_int; x > 1; x >>= 1) { | |
mask_size++; | |
} | |
bits_per_int--; | |
unsigned int arr_length; | |
unsigned int max; | |
arr_length = (length / bits_per_int) + 1; | |
unsigned int primes[arr_length]; | |
unsigned int index; | |
unsigned int bit; | |
unsigned int n; | |
memset(primes, 0, arr_length); | |
// only need to go sqrt of the array length | |
// since all divisors larger than the sqrt will | |
// have already been processed | |
max = sqrt(length); | |
for (int i = 2; i <= max; i++) { | |
n = i * i; | |
index = i >> mask_size; | |
bit = 1 << (i & bits_per_int); | |
if ((primes[index] & bit) == 0) { | |
while (n < length) { | |
n += i; | |
index = n >> mask_size; | |
bit = 1 << (n & bits_per_int); | |
primes[index] |= bit; | |
} | |
} | |
} | |
for (int i = 0; i < length; i++) { | |
index = i >> mask_size; | |
bit = 1 << (i & bits_per_int); | |
if ((primes[index] & bit) == 0) { | |
printf("%d\n", i); | |
} | |
} | |
} | |
int main(int argc, char *argv[]) | |
{ | |
primes(120); | |
return 0; | |
} |
Thanks for the responses.
I wonder if using a signed integer was causing the problems with (n <
31) >> 5. That was giving me very strange values.
Could be. Don't know what your weird results were and what exactly you were trying to do with (n < 31) >> 5. It's common to do "sign extension" or "sign preservation" when shifting negative numbers, so the effect of the shift is equivalent to a multiply/divide by 2 (as it is for positive numbers).
A couple of optimizations:
- You can start n = i * i; since all lower multiples of i will have been crossed off by previous values of i. E.g., no need to start at 6 when crossing off multiples of 3, since 2 already took care of it.
- You can stop your outer loop at sqrt(length) instead of half (but make sure the loop actually goes up to and includes square_root), since all divisors larger than square_root will have been crossed off by the smaller divisor pair. E.g. if length is 1000, the largest number you need to cross off multiples of is 31.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yeah, that's the sieve. A few issues I noticed and places to improve:
// something like this should do it
unsigned int mask_size;
unsigned int x;
for (x = bits_per_int, mask_size = 0; x > 1; x >>= 1) {
mask_size++;
}
mask_size will correctly be 5 for a 32-bit system, 6 for a 64-bit system, etc.