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