I am looking for a prime-sieve implementation which is efficient in terms of memory consumption.
Of course, the primality-test itself should execute at a constant and minimal number of operations.
I have implemented a sieve that indicates primality only for numbers that are adjacent to multiples of 6.
For any other number, either it is 2 or 3 (therefore prime), or it is a multiple of 2 or 3 (therefore non-prime).
So this is what I came up with, and I've been wondering if there is anything better under those requirements:
Interface:
#include <limits.h>
// Defined by the user (must be less than 'UINT_MAX')
#define RANGE 4000000000
// The actual length required for the prime-sieve array
#define ARR_LEN (((RANGE-1)/(3*CHAR_BIT)+1))
// Assumes that all entries in 'sieve' are initialized to zero
void Init(char sieve[ARR_LEN]);
// Assumes that 'Init(sieve)' has been called and that '1 < n < RANGE'
int IsPrime(char sieve[ARR_LEN],unsigned int n);
#if RANGE >= UINT_MAX
#error RANGE exceeds the limit
#endif
Implementation:
#include <math.h>
#define GET_BIT(sieve,n) ((sieve[(n)/(3*CHAR_BIT)]>>((n)%(3*CHAR_BIT)/3))&1)
#define SET_BIT(sieve,n) sieve[(n)/(3*CHAR_BIT)] |= 1<<((n)%(3*CHAR_BIT)/3)
static void InitOne(char sieve[ARR_LEN],int d)
{
unsigned int i,j;
unsigned int root = (unsigned int)sqrt((double)RANGE);
for (i=6+d; i<=root; i+=6)
{
if (GET_BIT(sieve,i) == 0)
{
for (j=6*i; j<RANGE; j+=6*i)
{
SET_BIT(sieve,j-i);
SET_BIT(sieve,j+i);
}
}
}
}
void Init(char sieve[ARR_LEN])
{
InitOne(sieve,-1);
InitOne(sieve,+1);
}
int IsPrime(char sieve[ARR_LEN],unsigned int n)
{
return n == 2 || n == 3 || (n%2 != 0 && n%3 != 0 && GET_BIT(sieve,n) == 0);
}