xref: /csrg-svn/games/primes/primes.c (revision 39969)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Landon Curt Noll.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #ifndef lint
22 char copyright[] =
23 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
24  All rights reserved.\n";
25 #endif /* not lint */
26 
27 #ifndef lint
28 static char sccsid[] = "@(#)primes.c	5.2 (Berkeley) 02/01/90";
29 #endif /* not lint */
30 
31 /*
32  * primes - generate a table of primes between two values
33  *
34  * By: Landon Curt Noll   chongo@toad.com,   ...!{sun,tolsoft}!hoptoad!chongo
35  *
36  *   chongo <for a good prime call: 391581 * 2^216193 - 1> /\oo/\
37  *
38  * usage:
39  *	primes [start [stop]]
40  *
41  *	Print primes >= start and <= stop.  If stop is omitted,
42  *	the value 4294967295 (2^32-1) is assumed.  If start is
43  *	omitted, start is read from standard input.
44  *
45  *	Prints "ouch" if start or stop is > 4294967295 (2^32-1)
46  *	or if a non-numeric is read on stdin.
47  *
48  * Validation check: there are 664579 primes between 0 and 10^7
49  */
50 
51 #include <stdio.h>
52 #include <math.h>
53 #include <memory.h>
54 #include <ctype.h>
55 #include "primes.h"
56 
57 /*
58  * Eratosthenes sieve table
59  *
60  * We only sieve the odd numbers.  The base of our sieve windows are always
61  * odd.  If the base of table is 1, table[i] represents 2*i-1.  After the
62  * sieve, table[i] == 1 if and only iff 2*i-1 is prime.
63  *
64  * We make TABSIZE large to reduce the overhead of inner loop setup.
65  */
66 char table[TABSIZE];	 /* Eratosthenes sieve of odd numbers */
67 
68 /*
69  * prime[i] is the (i-1)th prime.
70  *
71  * We are able to sieve 2^32-1 because this byte table yields all primes
72  * up to 65537 and 65537^2 > 2^32-1.
73  */
74 extern ubig prime[];
75 extern ubig *pr_limit;		/* largest prime in the prime array */
76 
77 /*
78  * To avoid excessive sieves for small factors, we use the table below to
79  * setup our sieve blocks.  Each element represents a odd number starting
80  * with 1.  All non-zero elements are factors of 3, 5, 7, 11 and 13.
81  */
82 extern char pattern[];
83 extern int pattern_size;	/* length of pattern array */
84 
85 #define MAX_LINE 255    /* max line allowed on stdin */
86 
87 char *read_num_buf();	 /* read a number buffer */
88 void primes();		 /* print the primes in range */
89 char *program;		 /* our name */
90 
91 main(argc, argv)
92 	int argc;	/* arg count */
93 	char *argv[];	/* args */
94 {
95 	char buf[MAX_LINE+1];   /* input buffer */
96 	char *ret;	/* return result */
97 	ubig start;	/* where to start generating */
98 	ubig stop;	/* don't generate at or above this value */
99 
100 	/*
101 	 * parse args
102 	 */
103 	program = argv[0];
104 	start = 0;
105 	stop = BIG;
106 	if (argc == 3) {
107 		/* convert low and high args */
108 		if (read_num_buf(NULL, argv[1]) == NULL) {
109 			fprintf(stderr, "%s: ouch\n", program);
110 			exit(1);
111 		}
112 		if (read_num_buf(NULL, argv[2]) == NULL) {
113 			fprintf(stderr, "%s: ouch\n", program);
114 			exit(1);
115 		}
116 		if (sscanf(argv[1], "%ld", &start) != 1) {
117 			fprintf(stderr, "%s: ouch\n", program);
118 			exit(1);
119 		}
120 		if (sscanf(argv[2], "%ld", &stop) != 1) {
121 			fprintf(stderr, "%s: ouch\n", program);
122 			exit(1);
123 		}
124 
125 	} else if (argc == 2) {
126 		/* convert low arg */
127 		if (read_num_buf(NULL, argv[1]) == NULL) {
128 			fprintf(stderr, "%s: ouch\n", program);
129 			exit(1);
130 		}
131 		if (sscanf(argv[1], "%ld", &start) != 1) {
132 			fprintf(stderr, "%s: ouch\n", program);
133 			exit(1);
134 		}
135 
136 	} else {
137 		/* read input until we get a good line */
138 		if (read_num_buf(stdin, buf) != NULL) {
139 
140 			/* convert the buffer */
141 			if (sscanf(buf, "%ld", &start) != 1) {
142 				fprintf(stderr, "%s: ouch\n", program);
143 				exit(1);
144 			}
145 		} else {
146 			exit(0);
147 		}
148 	}
149 	if (start > stop) {
150 		fprintf(stderr, "%s: ouch\n", program);
151 		exit(1);
152 	}
153 	primes(start, stop);
154 	exit(0);
155 }
156 
157 /*
158  * read_num_buf - read a number buffer from a stream
159  *
160  * Read a number on a line of the form:
161  *
162  *	^[ \t]*\(+?[0-9][0-9]\)*.*$
163  *
164  * where ? is a 1-or-0 operator and the number is within \( \).
165  *
166  * If does not match the above pattern, it is ignored and a new
167  * line is read.  If the number is too large or small, we will
168  * print ouch and read a new line.
169  *
170  * We have to be very careful on how we check the magnitude of the
171  * input.  We can not use numeric checks because of the need to
172  * check values against maximum numeric values.
173  *
174  * This routine will return a line containing a ascii number between
175  * 0 and BIG, or it will return NULL.
176  *
177  * If the stream is NULL then buf will be processed as if were
178  * a single line stream.
179  *
180  * returns:
181  *	char *	pointer to leading digit or +
182  *	NULL	EOF or error
183  */
184 char *
185 read_num_buf(input, buf)
186 	FILE *input;		/* input stream or NULL */
187 	char *buf;		/* input buffer */
188 {
189 	static char limit[MAX_LINE+1];	/* ascii value of BIG */
190 	static int limit_len;		/* digit count of limit */
191 	int len;			/* digits in input (excluding +/-) */
192 	char *s;	/* line start marker */
193 	char *d;	/* first digit, skip +/- */
194 	char *p;	/* scan pointer */
195 	char *z;	/* zero scan pointer */
196 
197 	/* form the ascii value of SEMIBIG if needed */
198 	if (!isascii(limit[0]) || !isdigit(limit[0])) {
199 		sprintf(limit, "%ld", SEMIBIG);
200 		limit_len = strlen(limit);
201 	}
202 
203 	/*
204 	 * the search for a good line
205 	 */
206 	if (input != NULL && fgets(buf, MAX_LINE, input) == NULL) {
207 		/* error or EOF */
208 		return NULL;
209 	}
210 	do {
211 
212 		/* ignore leading whitespace */
213 		for (s=buf; *s && s < buf+MAX_LINE; ++s) {
214 			if (!isascii(*s) || !isspace(*s)) {
215 				break;
216 			}
217 		}
218 
219 		/* object if - */
220 		if (*s == '-') {
221 			fprintf(stderr, "%s: ouch\n", program);
222 			continue;
223 		}
224 
225 		/* skip over any leading + */
226 		if (*s == '+') {
227 			d = s+1;
228 		} else {
229 			d = s;
230 		}
231 
232 		/* note leading zeros */
233 		for (z=d; *z && z < buf+MAX_LINE; ++z) {
234 			if (*z != '0') {
235 				break;
236 			}
237 		}
238 
239 		/* scan for the first non-digit/non-plus/non-minus */
240 		for (p=d; *p && p < buf+MAX_LINE; ++p) {
241 			if (!isascii(*p) || !isdigit(*p)) {
242 				break;
243 			}
244 		}
245 
246 		/* ignore empty lines */
247 		if (p == d) {
248 			continue;
249 		}
250 		*p = '\0';
251 
252 		/* object if too many digits */
253 		len = strlen(z);
254 		len = (len<=0) ? 1 : len;
255 		/* accept if digit count is below limit */
256 		if (len < limit_len) {
257 			/* we have good input */
258 			return s;
259 
260 		/* reject very large numbers */
261 		} else if (len > limit_len) {
262 			fprintf(stderr, "%s: ouch\n", program);
263 			continue;
264 
265 		/* carefully check against near limit numbers */
266 		} else if (strcmp(z, limit) > 0) {
267 			fprintf(stderr, "%s: ouch\n", program);
268 			continue;
269 		}
270 		/* number is near limit, but is under it */
271 		return s;
272 	} while (input != NULL && fgets(buf, MAX_LINE, input) != NULL);
273 
274 	/* error or EOF */
275 	return NULL;
276 }
277 
278 /*
279  * primes - sieve and print primes from start up to and but not including stop
280  */
281 void
282 primes(start, stop)
283 	ubig start;	/* where to start generating */
284 	ubig stop;	/* don't generate at or above this value */
285 {
286 	register char *q;		/* sieve spot */
287 	register ubig factor;		/* index and factor */
288 	register char *tab_lim;		/* the limit to sieve on the table */
289 	register ubig *p;		/* prime table pointer */
290 	register ubig fact_lim;		/* highest prime for current block */
291 
292 	/*
293 	 * A number of systems can not convert double values
294 	 * into unsigned longs when the values are larger than
295 	 * the largest signed value.  Thus we take case when
296 	 * the double is larger than the value SEMIBIG. *sigh*
297 	 */
298 	if (start < 3) {
299 		start = (ubig)2;
300 	}
301 	if (stop < 3) {
302 		stop = (ubig)2;
303 	}
304 	if (stop <= start) {
305 		return;
306 	}
307 
308 	/*
309 	 * be sure that the values are odd, or 2
310 	 */
311 	if (start != 2 && (start&0x1) == 0) {
312 		++start;
313 	}
314 	if (stop != 2 && (stop&0x1) == 0) {
315 		++stop;
316 	}
317 
318 	/*
319 	 * quick list of primes <= pr_limit
320 	 */
321 	if (start <= *pr_limit) {
322 		/* skip primes up to the start value */
323 		for (p = &prime[0], factor = prime[0];
324 		     factor < stop && p <= pr_limit;
325 		     factor = *(++p)) {
326 			if (factor >= start) {
327 				printf("%u\n", factor);
328 			}
329 		}
330 		/* return early if we are done */
331 		if (p <= pr_limit) {
332 			return;
333 		}
334 		start = *pr_limit+2;
335 	}
336 
337 	/*
338 	 * we shall sieve a bytemap window, note primes and move the window
339 	 * upward until we pass the stop point
340 	 */
341 	while (start < stop) {
342 		/*
343 		 * factor out 3, 5, 7, 11 and 13
344 		 */
345 		/* initial pattern copy */
346 		factor = (start%(2*3*5*7*11*13))/2; /* starting copy spot */
347 		memcpy(table, &pattern[factor], pattern_size-factor);
348 		/* main block pattern copies */
349 		for (fact_lim=pattern_size-factor;
350 		     fact_lim+pattern_size<=TABSIZE;
351 		     fact_lim+=pattern_size) {
352 			memcpy(&table[fact_lim], pattern, pattern_size);
353 		}
354 		/* final block pattern copy */
355 		memcpy(&table[fact_lim], pattern, TABSIZE-fact_lim);
356 
357 		/*
358 		 * sieve for primes 17 and higher
359 		 */
360 		/* note highest useful factor and sieve spot */
361 		if (stop-start > TABSIZE+TABSIZE) {
362 			tab_lim = &table[TABSIZE]; /* sieve it all */
363 			fact_lim = (int)sqrt(
364 					(double)(start)+TABSIZE+TABSIZE+1.0);
365 		} else {
366 			tab_lim = &table[(stop-start)/2]; /* partial sieve */
367 			fact_lim = (int)sqrt((double)(stop)+1.0);
368 		}
369 		/* sieve for factors >= 17 */
370 		factor = 17;	/* 17 is first prime to use */
371 		p = &prime[7];	/* 19 is next prime, pi(19)=7 */
372 		do {
373 			/* determine the factor's initial sieve point */
374 			q = (char *)(start%factor); /* temp storage for mod */
375 			if ((int)q & 0x1) {
376 				q = &table[(factor-(int)q)/2];
377 			} else {
378 				q = &table[q ? factor-((int)q/2) : 0];
379 			}
380 			/* sive for our current factor */
381 			for ( ; q < tab_lim; q += factor) {
382 				*q = '\0'; /* sieve out a spot */
383 			}
384 		} while ((factor=(ubig)(*(p++))) <= fact_lim);
385 
386 		/*
387 		 * print generated primes
388 		 */
389 		for (q = table; q < tab_lim; ++q, start+=2) {
390 			if (*q) {
391 				printf("%u\n", start);
392 			}
393 		}
394 	}
395 }
396