Annotation of OpenXM_contrib/gmp/demos/primes.c, Revision 1.1.1.2
1.1 maekawa 1: /* List and count primes.
1.1.1.2 ! ohara 2: Written by tege while on holiday in Rodupp, August 2001.
! 3: Between 10 and 500 times faster than previous program.
1.1 maekawa 4:
1.1.1.2 ! ohara 5: Copyright 2001 Free Software Foundation, Inc.
1.1 maekawa 6:
7: This program is free software; you can redistribute it and/or modify it under
8: the terms of the GNU General Public License as published by the Free Software
9: Foundation; either version 2 of the License, or (at your option) any later
10: version.
11:
12: This program is distributed in the hope that it will be useful, but WITHOUT ANY
13: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14: PARTICULAR PURPOSE. See the GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License along with
17: this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18: Place - Suite 330, Boston, MA 02111-1307, USA. */
19:
20: #include <stdlib.h>
21: #include <stdio.h>
1.1.1.2 ! ohara 22: #include <string.h>
! 23: #include <math.h>
! 24: #include <assert.h>
! 25:
! 26: /* IDEAS:
! 27: * Do not fill primes[] with real primes when the range [fr,to] is small,
! 28: when fr,to are relatively large. Fill primes[] with odd numbers instead.
! 29: [Probably a bad idea, since the primes[] array would become very large.]
! 30: * Separate small primes and large primes when sieving. Either the Montgomery
! 31: way (i.e., having a large array a multiple of L1 cache size), or just
! 32: separate loops for primes <= S and primes > S. The latter primes do not
! 33: require an inner loop, since they will touch the sieving array at most once.
! 34: * Pre-fill sieving array with an appropriately aligned ...00100100... pattern,
! 35: then omit 3 from primes array. (May require similar special handling of 3
! 36: as we now have for 2.)
! 37: * A large SIEVE_LIMIT currently implies very large memory usage, mainly due
! 38: to the sieving array in make_primelist, but also because of the primes[]
! 39: array. We might want to stage the program, using sieve_region/find_primes
! 40: to build primes[]. Make report() a function pointer, as part of achieving
! 41: this.
! 42: * Store primes[] as two arrays, one array with primes represented as delta
! 43: values using just 8 bits (if gaps are too big, store bogus primes!)
! 44: and one array with "rem" values. The latter needs 32-bit values.
! 45: * A new entry point, mpz_probab_prime_likely_p, would be useful.
! 46: * Improve command line syntax and versatility. "primes -f FROM -t TO",
! 47: allow either to be omitted for open interval. (But disallow
! 48: "primes -c -f FROM" since that would be infinity.) Allow printing a
! 49: limited *number* of primes using syntax like "primes -f FROM -n NUMBER".
! 50: * When looking for maxgaps, we should not perform any primality testing until
! 51: we find possible record gaps. Should speed up the searches tremendously.
! 52: */
! 53:
1.1 maekawa 54: #include "gmp.h"
55:
1.1.1.2 ! ohara 56: struct primes
! 57: {
! 58: unsigned int prime;
! 59: signed int rem;
! 60: };
! 61:
! 62: struct primes *primes;
! 63: unsigned long n_primes;
! 64:
! 65: void find_primes (unsigned char *, mpz_t, unsigned long, mpz_t);
! 66: void sieve_region (unsigned char *, mpz_t, unsigned long);
! 67: void make_primelist (unsigned long);
! 68:
! 69: int flag_print = 1;
! 70: int flag_count = 0;
! 71: int flag_maxgap = 0;
! 72: unsigned long maxgap = 0;
! 73: unsigned long total_primes = 0;
1.1 maekawa 74:
1.1.1.2 ! ohara 75: void
! 76: report (mpz_t prime)
1.1 maekawa 77: {
1.1.1.2 ! ohara 78: total_primes += 1;
! 79: if (flag_print)
! 80: {
! 81: mpz_out_str (stdout, 10, prime);
! 82: printf ("\n");
! 83: }
! 84: if (flag_maxgap)
! 85: {
! 86: static unsigned long prev_prime_low = 0;
! 87: unsigned long gap;
! 88: if (prev_prime_low != 0)
! 89: {
! 90: gap = mpz_get_ui (prime) - prev_prime_low;
! 91: if (maxgap < gap)
! 92: maxgap = gap;
! 93: }
! 94: prev_prime_low = mpz_get_ui (prime);
! 95: }
! 96: }
1.1 maekawa 97:
1.1.1.2 ! ohara 98: int
! 99: main (int argc, char *argv[])
! 100: {
! 101: char *progname = argv[0];
! 102: mpz_t fr, to;
! 103: mpz_t fr2, to2;
! 104: unsigned long sieve_lim;
! 105: unsigned long est_n_primes;
! 106: unsigned char *s;
! 107: mpz_t tmp;
! 108: mpz_t siev_sqr_lim;
1.1 maekawa 109:
110: while (argc != 1)
111: {
112: if (strcmp (argv[1], "-c") == 0)
113: {
114: flag_count = 1;
115: argv++;
116: argc--;
117: }
118: else if (strcmp (argv[1], "-p") == 0)
119: {
120: flag_print = 2;
121: argv++;
122: argc--;
123: }
1.1.1.2 ! ohara 124: else if (strcmp (argv[1], "-g") == 0)
! 125: {
! 126: flag_maxgap = 1;
! 127: argv++;
! 128: argc--;
! 129: }
1.1 maekawa 130: else
131: break;
132: }
133:
1.1.1.2 ! ohara 134: if (flag_count || flag_maxgap)
1.1 maekawa 135: flag_print--; /* clear unless an explicit -p */
136:
1.1.1.2 ! ohara 137: mpz_init (fr);
! 138: mpz_init (to);
! 139: mpz_init (fr2);
! 140: mpz_init (to2);
1.1 maekawa 141:
1.1.1.2 ! ohara 142: if (argc == 3)
1.1 maekawa 143: {
1.1.1.2 ! ohara 144: mpz_set_str (fr, argv[1], 0);
1.1 maekawa 145: if (argv[2][0] == '+')
146: {
1.1.1.2 ! ohara 147: mpz_set_str (to, argv[2] + 1, 0);
! 148: mpz_add (to, to, fr);
1.1 maekawa 149: }
150: else
1.1.1.2 ! ohara 151: mpz_set_str (to, argv[2], 0);
! 152: }
! 153: else if (argc == 2)
! 154: {
! 155: mpz_set_ui (fr, 0);
! 156: mpz_set_str (to, argv[1], 0);
1.1 maekawa 157: }
158: else
159: {
1.1.1.2 ! ohara 160: fprintf (stderr, "usage: %s [-c] [-p] [-g] [from [+]]to\n", progname);
1.1 maekawa 161: exit (1);
162: }
163:
1.1.1.2 ! ohara 164: mpz_set (fr2, fr);
! 165: if (mpz_cmp_ui (fr2, 3) < 0)
! 166: {
! 167: mpz_set_ui (fr2, 2);
! 168: report (fr2);
! 169: mpz_set_ui (fr2, 3);
! 170: }
! 171: mpz_setbit (fr2, 0); /* make odd */
! 172: mpz_sub_ui (to2, to, 1);
! 173: mpz_setbit (to2, 0); /* make odd */
! 174:
! 175: mpz_init (tmp);
! 176: mpz_init (siev_sqr_lim);
! 177:
! 178: mpz_sqrt (tmp, to2);
! 179: #define SIEVE_LIMIT 10000000
! 180: if (mpz_cmp_ui (tmp, SIEVE_LIMIT) < 0)
! 181: {
! 182: sieve_lim = mpz_get_ui (tmp);
! 183: }
! 184: else
! 185: {
! 186: sieve_lim = SIEVE_LIMIT;
! 187: mpz_sub (tmp, to2, fr2);
! 188: if (mpz_cmp_ui (tmp, sieve_lim) < 0)
! 189: sieve_lim = mpz_get_ui (tmp); /* limit sieving for small ranges */
! 190: }
! 191: mpz_set_ui (siev_sqr_lim, sieve_lim + 1);
! 192: mpz_mul_ui (siev_sqr_lim, siev_sqr_lim, sieve_lim + 1);
1.1 maekawa 193:
1.1.1.2 ! ohara 194: est_n_primes = (size_t) (sieve_lim / log((double) sieve_lim) * 1.13) + 10;
! 195: primes = malloc (est_n_primes * sizeof primes[0]);
! 196: make_primelist (sieve_lim);
! 197: assert (est_n_primes >= n_primes);
! 198:
! 199: #if DEBUG
! 200: printf ("sieve_lim = %lu\n", sieve_lim);
! 201: printf ("n_primes = %lu (3..%u)\n",
! 202: n_primes, primes[n_primes - 1].prime);
! 203: #endif
! 204:
! 205: #define S (1 << 15) /* FIXME: Figure out L1 cache size */
! 206: s = malloc (S/2);
! 207: while (mpz_cmp (fr2, to2) <= 0)
1.1 maekawa 208: {
1.1.1.2 ! ohara 209: unsigned long rsize;
! 210: rsize = S;
! 211: mpz_add_ui (tmp, fr2, rsize);
! 212: if (mpz_cmp (tmp, to2) > 0)
1.1 maekawa 213: {
1.1.1.2 ! ohara 214: mpz_sub (tmp, to2, fr2);
! 215: rsize = mpz_get_ui (tmp) + 2;
1.1 maekawa 216: }
1.1.1.2 ! ohara 217: #if DEBUG
! 218: printf ("Sieving region ["); mpz_out_str (stdout, 10, fr2);
! 219: printf (","); mpz_add_ui (tmp, fr2, rsize - 2);
! 220: mpz_out_str (stdout, 10, tmp); printf ("]\n");
! 221: #endif
! 222: sieve_region (s, fr2, rsize);
! 223: find_primes (s, fr2, rsize / 2, siev_sqr_lim);
! 224:
! 225: mpz_add_ui (fr2, fr2, S);
1.1 maekawa 226: }
1.1.1.2 ! ohara 227: free (s);
! 228:
! 229: if (flag_count)
! 230: printf ("Pi(interval) = %lu\n", total_primes);
! 231:
! 232: if (flag_maxgap)
! 233: printf ("max gap: %lu\n", maxgap);
1.1 maekawa 234:
1.1.1.2 ! ohara 235: return 0;
! 236: }
1.1 maekawa 237:
1.1.1.2 ! ohara 238: /* Find primes in region [fr,fr+rsize). Requires that fr is odd and that
! 239: rsize is even. The sieving array s should be aligned for "long int" and
! 240: have rsize/2 entries, rounded up to the nearest multiple of "long int". */
! 241: void
! 242: sieve_region (unsigned char *s, mpz_t fr, unsigned long rsize)
! 243: {
! 244: unsigned long ssize = rsize / 2;
! 245: unsigned long start, start2, prime;
! 246: unsigned long i;
! 247: mpz_t tmp;
! 248:
! 249: mpz_init (tmp);
! 250:
! 251: #if 0
! 252: /* initialize sieving array */
! 253: for (ii = 0; ii < (ssize + sizeof (long) - 1) / sizeof (long); ii++)
! 254: ((long *) s) [ii] = ~0L;
! 255: #else
! 256: {
! 257: signed long k;
! 258: long *se = (long *) (s + ((ssize + sizeof (long) - 1) & -sizeof (long)));
! 259: for (k = -((ssize + sizeof (long) - 1) / sizeof (long)); k < 0; k++)
! 260: se[k] = ~0L;
! 261: }
! 262: #endif
! 263:
! 264: for (i = 0; i < n_primes; i++)
1.1 maekawa 265: {
1.1.1.2 ! ohara 266: prime = primes[i].prime;
! 267:
! 268: if (primes[i].rem >= 0)
1.1 maekawa 269: {
1.1.1.2 ! ohara 270: start2 = primes[i].rem;
1.1 maekawa 271: }
1.1.1.2 ! ohara 272: else
! 273: {
! 274: mpz_set_ui (tmp, prime);
! 275: mpz_mul_ui (tmp, tmp, prime);
! 276: if (mpz_cmp (fr, tmp) <= 0)
! 277: {
! 278: mpz_sub (tmp, tmp, fr);
! 279: if (mpz_cmp_ui (tmp, 2 * ssize) > 0)
! 280: break; /* avoid overflow at next line, also speedup */
! 281: start = mpz_get_ui (tmp);
! 282: }
! 283: else
! 284: {
! 285: start = (prime - mpz_tdiv_ui (fr, prime)) % prime;
! 286: if (start % 2 != 0)
! 287: start += prime; /* adjust if even divisable */
! 288: }
! 289: start2 = start / 2;
! 290: }
! 291:
! 292: #if 0
! 293: for (ii = start2; ii < ssize; ii += prime)
! 294: s[ii] = 0;
! 295: primes[i].rem = ii - ssize;
! 296: #else
! 297: {
! 298: signed long k;
! 299: unsigned char *se = s + ssize; /* point just beyond sieving range */
! 300: for (k = start2 - ssize; k < 0; k += prime)
! 301: se[k] = 0;
! 302: primes[i].rem = k;
! 303: }
! 304: #endif
! 305: }
! 306: mpz_clear (tmp);
! 307: }
! 308:
! 309: /* Find primes in region [fr,fr+rsize), using the previously sieved s[]. */
! 310: void
! 311: find_primes (unsigned char *s, mpz_t fr, unsigned long ssize,
! 312: mpz_t siev_sqr_lim)
! 313: {
! 314: unsigned long j, ij;
! 315: mpz_t tmp;
! 316:
! 317: mpz_init (tmp);
! 318: for (j = 0; j < (ssize + sizeof (long) - 1) / sizeof (long); j++)
! 319: {
! 320: if (((long *) s) [j] != 0)
1.1 maekawa 321: {
1.1.1.2 ! ohara 322: for (ij = 0; ij < sizeof (long); ij++)
1.1 maekawa 323: {
1.1.1.2 ! ohara 324: if (s[j * sizeof (long) + ij] != 0)
1.1 maekawa 325: {
1.1.1.2 ! ohara 326: if (j * sizeof (long) + ij >= ssize)
! 327: goto out;
! 328: mpz_add_ui (tmp, fr, (j * sizeof (long) + ij) * 2);
! 329: if (mpz_cmp (tmp, siev_sqr_lim) < 0 ||
! 330: mpz_probab_prime_p (tmp, 3))
! 331: report (tmp);
1.1 maekawa 332: }
333: }
334: }
335: }
1.1.1.2 ! ohara 336: out:
! 337: mpz_clear (tmp);
! 338: }
! 339:
! 340: /* Generate a lits of primes and store in the global array primes[]. */
! 341: void
! 342: make_primelist (unsigned long maxprime)
! 343: {
! 344: #if 1
! 345: unsigned char *s;
! 346: unsigned long ssize = maxprime / 2;
! 347: unsigned long i, ii, j;
! 348:
! 349: s = malloc (ssize);
! 350: memset (s, ~0, ssize);
! 351: for (i = 3; ; i += 2)
! 352: {
! 353: unsigned long isqr = i * i;
! 354: if (isqr >= maxprime)
! 355: break;
! 356: if (s[i * i / 2 - 1] == 0)
! 357: continue; /* only sieve with primes */
! 358: for (ii = i * i / 2 - 1; ii < ssize; ii += i)
! 359: s[ii] = 0;
! 360: }
! 361: n_primes = 0;
! 362: for (j = 0; j < ssize; j++)
! 363: {
! 364: if (s[j] != 0)
! 365: {
! 366: primes[n_primes].prime = j * 2 + 3;
! 367: primes[n_primes].rem = -1;
! 368: n_primes++;
! 369: }
! 370: }
! 371: /* FIXME: This should not be needed if fencepost errors were fixed... */
! 372: if (primes[n_primes - 1].prime > maxprime)
! 373: n_primes--;
! 374: free (s);
! 375: #else
! 376: unsigned long i;
! 377: n_primes = 0;
! 378: for (i = 3; i <= maxprime; i += 2)
! 379: {
! 380: if (i < 7 || (i % 3 != 0 && i % 5 != 0 && i % 7 != 0))
! 381: {
! 382: primes[n_primes].prime = i;
! 383: primes[n_primes].rem = -1;
! 384: n_primes++;
! 385: }
! 386: }
! 387: #endif
1.1 maekawa 388: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>