Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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

563641 views
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 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 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., 51 Franklin
18
Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20
#include <stdlib.h>
21
#include <stdio.h>
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
54
#include "gmp.h"
55
56
struct primes
57
{
58
unsigned int prime;
59
int rem;
60
};
61
62
struct primes *primes;
63
unsigned long n_primes;
64
65
void find_primes __GMP_PROTO ((unsigned char *, mpz_t, unsigned long, mpz_t));
66
void sieve_region __GMP_PROTO ((unsigned char *, mpz_t, unsigned long));
67
void make_primelist __GMP_PROTO ((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;
74
75
void
76
report (mpz_t prime)
77
{
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
}
97
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;
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
}
124
else if (strcmp (argv[1], "-g") == 0)
125
{
126
flag_maxgap = 1;
127
argv++;
128
argc--;
129
}
130
else
131
break;
132
}
133
134
if (flag_count || flag_maxgap)
135
flag_print--; /* clear unless an explicit -p */
136
137
mpz_init (fr);
138
mpz_init (to);
139
mpz_init (fr2);
140
mpz_init (to2);
141
142
if (argc == 3)
143
{
144
mpz_set_str (fr, argv[1], 0);
145
if (argv[2][0] == '+')
146
{
147
mpz_set_str (to, argv[2] + 1, 0);
148
mpz_add (to, to, fr);
149
}
150
else
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);
157
}
158
else
159
{
160
fprintf (stderr, "usage: %s [-c] [-p] [-g] [from [+]]to\n", progname);
161
exit (1);
162
}
163
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);
193
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)
208
{
209
unsigned long rsize;
210
rsize = S;
211
mpz_add_ui (tmp, fr2, rsize);
212
if (mpz_cmp (tmp, to2) > 0)
213
{
214
mpz_sub (tmp, to2, fr2);
215
rsize = mpz_get_ui (tmp) + 2;
216
}
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);
226
}
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);
234
235
return 0;
236
}
237
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
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++)
265
{
266
prime = primes[i].prime;
267
268
if (primes[i].rem >= 0)
269
{
270
start2 = primes[i].rem;
271
}
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
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)
321
{
322
for (ij = 0; ij < sizeof (long); ij++)
323
{
324
if (s[j * sizeof (long) + ij] != 0)
325
{
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);
332
}
333
}
334
}
335
}
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
388
}
389
390