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