First 250,000 prime numbers with C source code
My son is learning C, and I challenged him to write a program that would ask the user for a positive integer, and the program would calculate if the number was prime. He was able to do it, but during our discussion, I was trying to get him to think about at what number he should stop doing test divides. But his mind became wedged on a problem after he quickly realized that the you only had to test divide the prospective prime numbers by smaller prime numbers. Since his program was to calculate if the user-entered prospective prime was actually prime, he thought having a list of primes would be cheating. He eventually explained what was distracting him, which of course surprised me, given the deep esoteric nature of his thinking. Anyway, he soon realized he could just use the odd numbers as a compromise for his program, and that stopping at the square root of the prospective prime was sufficient. Even so, his idea to only use smaller primes to test candidate primes was a great idea (he didn't invent this, but he did invent it independantly, in his head, after only a few minutes thought--which impresses a father.)
Anyway, I ripped off my son's idea, and wrote a program to rapidly enumerate all of the prime numbers, up to the 250,000th prime number, using smaller primes to test larger prospective primes. This was a different problem than the one I assigned my son, but I wanted to put his idea into practice.
The program I wrote takes only a few seconds to enumerate a list of the first 250,000 primes, and write them to two files, one in binary, the other text. The speed of the program amazes me since my computer is a few years old. When I worked on such programs when I was in school, they would take much longer to run. The speed up is mostly due to advances in computer hardware since then, though my son's algorithm does speed things up for equal hardware--I estimate by a factor of 2 for the program below.
Here is a snipped of the last primes generated (complete lists are available for download below):
Number Prime Number ------ ------------ 249990 3497617 249991 3497623 249992 3497671 249993 3497713 249994 3497717 249995 3497743 249996 3497759 249997 3497779 249998 3497827 249999 3497849 250000 3497861
As promised, here are links to the first 250000 prime numbers in text format. If possible, please download one of the zipped versions to save bandwidth:
- The first 250,000 prime numbers in binary format, compressed. (726kB Zipped text recommended)
- The first 250,000 prime numbers in binary format, compressed. (338kB Zipped binary in little endian)
- The first 250,000 prime numbers in text format (3,907kB uncompressed, larger file, not recommended)
And now for the quickly written source code to generate the primes.
/*
* program to generate primes by testing prospective
* primes against previously enumerated primes
*/
#include "stdafx.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define DO_FAST 1
#define CONSOLE_OUTPUT 0
#define NUMPRIMES 250000
typedef unsigned long UINT32;
void hit_return_to_continue();
bool is_pp_p(UINT32 *primes, UINT32 npf, UINT32 pp, UINT32 *miu );
int _tmain(int argc, _TCHAR* argv[])
{
UINT32 primes[NUMPRIMES];
UINT32 pp; /* prospective prime */
UINT32 npf; /* number of primes found */
UINT32 miu=0; /* max index used, that is, max indextinto primes ever used to calculate primes */
UINT32 i;
/* initialize first two primes and the number of primes found */
primes[0] = 2;
primes[1] = 3;
npf = 2;
/* recursively compile the first NUMPRIMES prime numbers, and save them */
for(pp=primes[1]+2;npf<NUMPRIMES;pp+=2){
if(is_pp_p(primes,npf,pp,&miu))
npf++;
}
if(CONSOLE_OUTPUT){
/*
*print out book keeping regarding maximum index used
*/
printf("\n");
printf("The maximum index into the list of prime numbers we\n");
printf("used to generate the first %ld prime numbers was %ld.\n",NUMPRIMES,miu);
printf("The prime number at this index is %ld.\n\n",primes[miu]);
{
unsigned long long alpp;/* approximately largest prospective prime that we can evaluate using this method */
alpp=(((unsigned long long)primes[NUMPRIMES-1]*(unsigned long long)primes[NUMPRIMES-1]) - 2)|1;
printf("The biggest prospective prime we will be able to\n");
printf("evaluate, using this method and a list of %ld\n",NUMPRIMES);
printf("prime numbers, will be approximately: %lld.\n\n",alpp);
}
}
/* create txt and binary files of NUMPRIMES prime numbers */
{
FILE *fptr_txt=NULL;
FILE *fptr_bin=NULL;
fptr_txt=fopen("primes.txt","w");
fptr_bin=fopen("primes.bin","wb");
if(fptr_bin==NULL || fptr_txt==NULL){
printf("Cannot write the files, closing.\n");
if(fptr_bin!=NULL)
fclose(fptr_bin);
if(fptr_txt!=NULL)
fclose(fptr_txt);
}else{
/* write text file */
for(i=0;i<NUMPRIMES;i++){
fprintf(fptr_txt,"%6ld %7ld\n",i+1,primes[i]);
}
fclose(fptr_txt);
/* write binary file */
fwrite(primes,sizeof(UINT32),NUMPRIMES,fptr_bin);
fclose(fptr_bin);
}
}
/* pause for return for windows run */
hit_return_to_continue();
return 0;
}
/* is the prospective prime really prime */
bool is_pp_p(UINT32 *primes, UINT32 npf, UINT32 pp, UINT32 *miu )
{
bool rval=true;
UINT32 i;
UINT32 end;
/* no need to check primes larger than square root of candidate prime */
end = (UINT32)sqrt((float)pp);
/* check to see if the candidate prime is divisable by previous primes */
if(DO_FAST == 1){
/* divide by primes */
for(i=0;primes[i]<=end && rval;i++)
if(0 == pp%primes[i])
rval=false;
}else{
/* divide by odd numbers */
for(i=3;i<=end && rval;i+=2)
if(0 == pp%i)
rval=false;
}
/* save i if it is greater than previous maximum index used, to keep track index to largest prime used so far */
if(i > *miu){
*miu=i;
if(CONSOLE_OUTPUT )
printf("New miu=%ld.\n",*miu);
}
if(rval){
/* we found a prime, save it to our list */
primes[npf]=pp;
if(CONSOLE_OUTPUT)
printf("%6ld, %ld \n",npf+1,pp);
}
return rval;
}
void hit_return_to_continue()
{
printf("\nhit return to continue.\n");
fflush(stdin);
getchar();
}




Recent Comments