primes.c revision 1.1 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 mrg Copyright 2001, 2002, 2006 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 mrg this program. If not, see http://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 mrg void find_primes __GMP_PROTO ((unsigned char *, mpz_t, unsigned long, mpz_t));
65 1.1 mrg void sieve_region __GMP_PROTO ((unsigned char *, mpz_t, unsigned long));
66 1.1 mrg void make_primelist __GMP_PROTO ((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