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