]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - primes/primes.c
Sync to 4.4BSD-Lite2
[bsdgames-darwin.git] / primes / primes.c
1 /* $NetBSD: primes.c,v 1.6 1997/01/07 12:24:57 tls Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Landon Curt Noll.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 static char copyright[] =
41 "@(#) Copyright (c) 1989, 1993\n\
42 The Regents of the University of California. All rights reserved.\n";
43 #endif /* not lint */
44
45 #ifndef lint
46 #if 0
47 static char sccsid[] = "@(#)primes.c 8.5 (Berkeley) 5/10/95";
48 #else
49 static char rcsid[] = "$NetBSD: primes.c,v 1.6 1997/01/07 12:24:57 tls Exp $";
50 #endif
51 #endif /* not lint */
52
53 /*
54 * primes - generate a table of primes between two values
55 *
56 * By: Landon Curt Noll chongo@toad.com, ...!{sun,tolsoft}!hoptoad!chongo
57 *
58 * chongo <for a good prime call: 391581 * 2^216193 - 1> /\oo/\
59 *
60 * usage:
61 * primes [start [stop]]
62 *
63 * Print primes >= start and < stop. If stop is omitted,
64 * the value 4294967295 (2^32-1) is assumed. If start is
65 * omitted, start is read from standard input.
66 *
67 * validation check: there are 664579 primes between 0 and 10^7
68 */
69
70 #include <ctype.h>
71 #include <err.h>
72 #include <errno.h>
73 #include <limits.h>
74 #include <math.h>
75 #include <memory.h>
76 #include <stdio.h>
77 #include <stdlib.h>
78 #include <unistd.h>
79
80 #include "primes.h"
81
82 /*
83 * Eratosthenes sieve table
84 *
85 * We only sieve the odd numbers. The base of our sieve windows are always
86 * odd. If the base of table is 1, table[i] represents 2*i-1. After the
87 * sieve, table[i] == 1 if and only iff 2*i-1 is prime.
88 *
89 * We make TABSIZE large to reduce the overhead of inner loop setup.
90 */
91 char table[TABSIZE]; /* Eratosthenes sieve of odd numbers */
92
93 /*
94 * prime[i] is the (i-1)th prime.
95 *
96 * We are able to sieve 2^32-1 because this byte table yields all primes
97 * up to 65537 and 65537^2 > 2^32-1.
98 */
99 extern ubig prime[];
100 extern ubig *pr_limit; /* largest prime in the prime array */
101
102 /*
103 * To avoid excessive sieves for small factors, we use the table below to
104 * setup our sieve blocks. Each element represents a odd number starting
105 * with 1. All non-zero elements are factors of 3, 5, 7, 11 and 13.
106 */
107 extern char pattern[];
108 extern int pattern_size; /* length of pattern array */
109
110 void primes __P((ubig, ubig));
111 ubig read_num_buf __P((void));
112 void usage __P((void));
113
114 int
115 main(argc, argv)
116 int argc;
117 char *argv[];
118 {
119 ubig start; /* where to start generating */
120 ubig stop; /* don't generate at or above this value */
121 int ch;
122 char *p;
123
124 while ((ch = getopt(argc, argv, "")) != EOF)
125 switch (ch) {
126 case '?':
127 default:
128 usage();
129 }
130 argc -= optind;
131 argv += optind;
132
133 start = 0;
134 stop = BIG;
135
136 /*
137 * Convert low and high args. Strtoul(3) sets errno to
138 * ERANGE if the number is too large, but, if there's
139 * a leading minus sign it returns the negation of the
140 * result of the conversion, which we'd rather disallow.
141 */
142 switch (argc) {
143 case 2:
144 /* Start and stop supplied on the command line. */
145 if (argv[0][0] == '-' || argv[1][0] == '-')
146 errx(1, "negative numbers aren't permitted.");
147
148 errno = 0;
149 start = strtoul(argv[0], &p, 10);
150 if (errno)
151 err(1, "%s", argv[0]);
152 if (*p != '\0')
153 errx(1, "%s: illegal numeric format.", argv[0]);
154
155 errno = 0;
156 stop = strtoul(argv[1], &p, 10);
157 if (errno)
158 err(1, "%s", argv[1]);
159 if (*p != '\0')
160 errx(1, "%s: illegal numeric format.", argv[1]);
161 break;
162 case 1:
163 /* Start on the command line. */
164 if (argv[0][0] == '-')
165 errx(1, "negative numbers aren't permitted.");
166
167 errno = 0;
168 start = strtoul(argv[0], &p, 10);
169 if (errno)
170 err(1, "%s", argv[0]);
171 if (*p != '\0')
172 errx(1, "%s: illegal numeric format.", argv[0]);
173 break;
174 case 0:
175 start = read_num_buf();
176 break;
177 default:
178 usage();
179 }
180
181 if (start > stop)
182 errx(1, "start value must be less than stop value.");
183 primes(start, stop);
184 exit(0);
185 }
186
187 /*
188 * read_num_buf --
189 * This routine returns a number n, where 0 <= n && n <= BIG.
190 */
191 ubig
192 read_num_buf()
193 {
194 ubig val;
195 char *p, buf[100]; /* > max number of digits. */
196
197 for (;;) {
198 if (fgets(buf, sizeof(buf), stdin) == NULL) {
199 if (ferror(stdin))
200 err(1, "stdin");
201 exit(0);
202 }
203 for (p = buf; isblank(*p); ++p);
204 if (*p == '\n' || *p == '\0')
205 continue;
206 if (*p == '-')
207 errx(1, "negative numbers aren't permitted.");
208 errno = 0;
209 val = strtoul(buf, &p, 10);
210 if (errno)
211 err(1, "%s", buf);
212 if (*p != '\n')
213 errx(1, "%s: illegal numeric format.", buf);
214 return (val);
215 }
216 }
217
218 /*
219 * primes - sieve and print primes from start up to and but not including stop
220 */
221 void
222 primes(start, stop)
223 ubig start; /* where to start generating */
224 ubig stop; /* don't generate at or above this value */
225 {
226 register char *q; /* sieve spot */
227 register ubig factor; /* index and factor */
228 register char *tab_lim; /* the limit to sieve on the table */
229 register ubig *p; /* prime table pointer */
230 register ubig fact_lim; /* highest prime for current block */
231
232 /*
233 * A number of systems can not convert double values into unsigned
234 * longs when the values are larger than the largest signed value.
235 * We don't have this problem, so we can go all the way to BIG.
236 */
237 if (start < 3) {
238 start = (ubig)2;
239 }
240 if (stop < 3) {
241 stop = (ubig)2;
242 }
243 if (stop <= start) {
244 return;
245 }
246
247 /*
248 * be sure that the values are odd, or 2
249 */
250 if (start != 2 && (start&0x1) == 0) {
251 ++start;
252 }
253 if (stop != 2 && (stop&0x1) == 0) {
254 ++stop;
255 }
256
257 /*
258 * quick list of primes <= pr_limit
259 */
260 if (start <= *pr_limit) {
261 /* skip primes up to the start value */
262 for (p = &prime[0], factor = prime[0];
263 factor < stop && p <= pr_limit; factor = *(++p)) {
264 if (factor >= start) {
265 printf("%u\n", factor);
266 }
267 }
268 /* return early if we are done */
269 if (p <= pr_limit) {
270 return;
271 }
272 start = *pr_limit+2;
273 }
274
275 /*
276 * we shall sieve a bytemap window, note primes and move the window
277 * upward until we pass the stop point
278 */
279 while (start < stop) {
280 /*
281 * factor out 3, 5, 7, 11 and 13
282 */
283 /* initial pattern copy */
284 factor = (start%(2*3*5*7*11*13))/2; /* starting copy spot */
285 memcpy(table, &pattern[factor], pattern_size-factor);
286 /* main block pattern copies */
287 for (fact_lim=pattern_size-factor;
288 fact_lim+pattern_size<=TABSIZE; fact_lim+=pattern_size) {
289 memcpy(&table[fact_lim], pattern, pattern_size);
290 }
291 /* final block pattern copy */
292 memcpy(&table[fact_lim], pattern, TABSIZE-fact_lim);
293
294 /*
295 * sieve for primes 17 and higher
296 */
297 /* note highest useful factor and sieve spot */
298 if (stop-start > TABSIZE+TABSIZE) {
299 tab_lim = &table[TABSIZE]; /* sieve it all */
300 fact_lim = (int)sqrt(
301 (double)(start)+TABSIZE+TABSIZE+1.0);
302 } else {
303 tab_lim = &table[(stop-start)/2]; /* partial sieve */
304 fact_lim = (int)sqrt((double)(stop)+1.0);
305 }
306 /* sieve for factors >= 17 */
307 factor = 17; /* 17 is first prime to use */
308 p = &prime[7]; /* 19 is next prime, pi(19)=7 */
309 do {
310 /* determine the factor's initial sieve point */
311 q = (char *)(start%factor); /* temp storage for mod */
312 if ((long)q & 0x1) {
313 q = &table[(factor-(long)q)/2];
314 } else {
315 q = &table[q ? factor-((long)q/2) : 0];
316 }
317 /* sive for our current factor */
318 for ( ; q < tab_lim; q += factor) {
319 *q = '\0'; /* sieve out a spot */
320 }
321 } while ((factor=(ubig)(*(p++))) <= fact_lim);
322
323 /*
324 * print generated primes
325 */
326 for (q = table; q < tab_lim; ++q, start+=2) {
327 if (*q) {
328 printf("%u\n", start);
329 }
330 }
331 }
332 }
333
334 void
335 usage()
336 {
337 (void)fprintf(stderr, "usage: primes [start [stop]]\n");
338 exit(1);
339 }