Primality Testing — Part 2. Pre-computation with Sieve of Eratosthenes
Previous post covers two naive methods for primality testing. This post introduces an algorithm to generate prime numbers called Sieve of Eratosthenes. With this algorithm, an optimization can be applied to speed up the primality testing.
Sieve of Eratosthenes
Suppose we want to generate prime numbers up to N. The algorithm consists of two loops, and it can be described as below,
- Create a mask for all integers up to N.
- In the first loop, let x be 2, mark 2x, 3x, 4x for all n such that nx < N.
- finding an integer bigger than x and not marked, let it be the new x, and repeat the step above
- the first loop terminates when we cannot find an integer bigger than x and not marked
- In the second loop, starting from 2, collects the numbers that are not marked, which are the prime numbers up to N.
Below is an implementation of the Sieve of Eratosthenes algorithm,
/**
generate prime numbers
**/
#include <stdio.h>
#include <stdlib.h>
#define MAXV 10000000
#define ININ 1000
unsigned char bits[MAXV/8];
void setbit(int pos) {
bits[pos/8] |= (0x01 << (pos%8));
}
int testbit(int pos) {
return (bits[pos/8] & (0x01 << (pos%8)));
}
void genprime(int n, int **pr, int *npr) {
int i, j, k;
for (i = 2; i < n; ++i) {
if (!testbit(i)) {
for (j = 2; i*j < n; ++j) {
setbit(i*j);
}
}
}
k = ININ;
*pr = malloc(sizeof(int) * k);
*npr = 0;
for (i = 2, j = 0; i < n; ++i) {
if (!testbit(i)) {
(*pr)[j++] = i;
(*npr)++;
if (j == k) {
k += ININ;
*pr = realloc(*pr, sizeof(int)*k);
}
}
}
}
int main(int argc, char **argv) {
int n = atoi(argv[1]);
int *pr;
int npr;
int i;
struct timeval stTime, edTime;
if (n > MAXV) {
printf("the max n is %d\n", MAXV);
return 0;
}
gettimeofday(&stTime, NULL);
genprime(n, &pr, &npr);
printf("No. of prime numbers: %d\n", npr);
for (i = 0; i < npr; ++i) {
printf("%d ", pr[i]);
}
printf("\n");
gettimeofday(&edTime, NULL);
printf("time: %u:%u\n", (unsigned int)(edTime.tv_sec - stTime.tv_sec), (unsigned int)(edTime.tv_usec - stTime.tv_usec));
if (pr != NULL) {
free(pr);
}
return 0;
}
Note that the code above use a single bit to indicate if an integer is marked or not.
Save the code to prim2.c, and then compile the code with the command below,
gcc -o prim2 prim2.c
Below is a screenshot of some simple tests,
Figure 1. Simple Tests of Implementation for Sieve of Eratosthenes
Primality Testing with Sieve of Eratosthenes for Precomputation
One way to speed up primality testing is to precompute a list of prime numbers up to N. Then we first check if an input integer n is divisible by the prime numbers generated. If the number is not divisible by any of those prime numbers, we then proceed to the test mentioned in the naive approach post.
Below is an implementation of this precomputation approach,
/**
a primality test with precomputation
**/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAXV 10000000
#define ININ 1000
unsigned char bits[MAXV/8];
void setbit(int pos) {
bits[pos/8] |= (0x01 << (pos%8));
}
int testbit(int pos) {
return (bits[pos/8] & (0x01 << (pos%8)));
}
void genprime(int n, int **pr, int *npr) {
int i, j, k;
for (i = 2; i < n; ++i) {
if (!testbit(i)) {
for (j = 2; i*j < n; ++j) {
setbit(i*j);
}
}
}
k = ININ;
*pr = malloc(sizeof(int) * k);
*npr = 0;
for (i = 2, j = 0; i < n; ++i) {
if (!testbit(i)) {
(*pr)[j++] = i;
(*npr)++;
if (j == k) {
k += ININ;
*pr = realloc(*pr, sizeof(int)*k);
}
}
}
}
int prime(int n, int *pr, int npr, int x) {
int i;
int j;
for (i = 0; i < npr; ++i) {
if (n == pr[i]) {
return 1;
}
if (n%pr[i] == 0) {
printf("%d is divisble by %d\n", n, pr[i]);
return 0;
}
}
if (n == 2) {
return 1;
}
if (!(n&1)) {
printf("%d is divisible by 2\n", n);
return 0;
}
j = sqrt(n);
//to be safe, run to j+1
i = (x+1) > 3 ? (x+1):3;
if (!(i&1)) {
++i; //make sure i starts as odd number
}
for (; i <= j + 1; i+=2) {
if (n%i == 0) {
printf("%d is divisible by %d\n", n, i);
return 0;
}
}
return 1;
}
int main(int argc, char **argv) {
int m, n;
int *pr;
int npr;
int i;
struct timeval stTime, stTime2, edTime;
if (argc < 3) {
printf("./prim3 <primality test number> <prime number generation limit>\n");
return 0;
}
m = atoi(argv[1]);
n = atoi(argv[2]);
if (n > MAXV) {
printf("the max n is %d\n", MAXV);
return 0;
}
gettimeofday(&stTime, NULL);
genprime(n, &pr, &npr);
gettimeofday(&stTime2, NULL);
//printf("No. of prime numbers: %d\n", npr);
/* for (i = 0; i < npr; ++i) {
printf("%d\n", pr[i]);
}*/
if (prime(m, pr, npr, n)) {
printf("%d is prime number\n", m);
} else {
printf("%d is not prime number\n", m);
}
gettimeofday(&edTime, NULL);
printf("total time: %u:%u\n", (unsigned int)(edTime.tv_sec - stTime.tv_sec), (unsigned int)(edTime.tv_usec - stTime.tv_usec));
printf("test prime time: %u:%u\n", (unsigned int)(edTime.tv_sec - stTime2.tv_sec), (unsigned int)(edTime.tv_usec - stTime2.tv_usec));
if (pr != NULL) {
free(pr);
}
return 0;
}
Save the source code to prim3.c, and then compile the code with the command below,
gcc -o prim3 prim3.c –lm
Below are some simple tests for the compiled program,
roman10@ra-ubuntu-1:~/Desktop/integer/prim$ ./prim3 2 10
2 is prime number
total time: 0:144
test prime time: 0:48
roman10@ra-ubuntu-1:~/Desktop/integer/prim$ ./prim3 3 10
3 is prime number
total time: 0:60
test prime time: 0:22
roman10@ra-ubuntu-1:~/Desktop/integer/prim$ ./prim3 2147483647 1000
2147483647 is prime number
total time: 0:469
test prime time: 0:302
roman10@ra-ubuntu-1:~/Desktop/integer/prim$ ./prim3 2147483643 1000
2147483643 is divisble by 3
2147483643 is not prime number
total time: 0:223
test prime time: 0:57
roman10@ra-ubuntu-1:~/Desktop/integer/prim$ ./prim3 2147483641 1000
2147483641 is divisible by 2699
2147483641 is not prime number
total time: 0:250
test prime time: 0:80
References:
1. Wikipedia: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
Leave a Reply Cancel reply
40% Discount on My Book — Android NDK Cookbook
Android NDK Cookbook ebook 40% discount with promotion code MREANC40 at Packt Publishing The promotion code is valid until 15th June.Categories
- Android Apps (18)
- Android Audio Editor (1)
- TS 2 (3)
- Video Converter Android (8)
- Video2Gif (1)
- Android Tutorial (27)
- Android Dev Tools (1)
- API illustrated (8)
- Multimedia API (3)
- ffmpeg on Android (4)
- NDK (6)
- UI (6)
- Animation (2)
- Code Snippet (2)
- Coding Beyond Technique (18)
- a word, a world (4)
- Bug Rectified (4)
- Programming Habit (1)
- Software as a Career (1)
- Software as User Experience (1)
- Compilers and Related (2)
- ELF (2)
- Computer Languages (31)
- C/C++ (13)
- Java (9)
- JavaScript (2)
- PHP (1)
- Python (8)
- Data Structure & Algorithms (29)
- Bits (1)
- Data Structure (5)
- Integers (10)
- BigInteger (1)
- Prime (4)
- Search (3)
- Sorting (5)
- Strings (5)
- Database (1)
- SQLite (1)
- Digital Signal Processing (33)
- Distributed Systems (17)
- Apache Cassandra (6)
- Apache Hadoop (8)
- Apache Avro (3)
- Apache Nutch (3)
- Apache Solr (1)
- Linux Study Notes (40)
- crontab (1)
- Linux Kernel Programming (8)
- Linux Programming (12)
- IPC (2)
- Linux Network Programming (5)
- Linux Signals (2)
- Linux Shell Scripting (1)
- ssh (3)
- Machinery (30)
- misc (1)
- My Ideas (1)
- My Project (3)
- Mobile Caching (1)
- Selective Decoding (2)
- My Publication (1)
- My Readings (1)
- Networking (15)
- Program for Performance (8)
- Uncategorized (1)
- Virtual Machine (2)
- Web Dev (8)
- web components (3)
- Android Apps (18)
Recent Comments
Archives
- May 2013 (2)
- April 2013 (1)
- March 2013 (4)
- December 2012 (2)
- November 2012 (6)
- October 2012 (6)
- September 2012 (3)
- August 2012 (13)
- July 2012 (15)
- June 2012 (3)
- May 2012 (8)
- April 2012 (4)
- March 2012 (13)
- February 2012 (19)
- January 2012 (9)
- December 2011 (11)
- November 2011 (12)
- October 2011 (4)
- September 2011 (12)
- August 2011 (16)
- July 2011 (15)
- June 2011 (6)
- May 2011 (10)
- April 2011 (13)
- March 2011 (20)
- February 2011 (4)
- November 2010 (2)
- May 2010 (1)
- April 2010 (1)
- February 2010 (1)




