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