CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

Views: 418346
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
}
388
389