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