Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
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
Project: cocalc-sagemath-dev-slelievre
Views: 418346/* List and count primes.1Written by tege while on holiday in Rodupp, August 2001.2Between 10 and 500 times faster than previous program.34Copyright 2001, 2002, 2006, 2012 Free Software Foundation, Inc.56This program is free software; you can redistribute it and/or modify it under7the terms of the GNU General Public License as published by the Free Software8Foundation; either version 3 of the License, or (at your option) any later9version.1011This program is distributed in the hope that it will be useful, but WITHOUT ANY12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A13PARTICULAR PURPOSE. See the GNU General Public License for more details.1415You should have received a copy of the GNU General Public License along with16this program. If not, see https://www.gnu.org/licenses/. */1718#include <stdlib.h>19#include <stdio.h>20#include <string.h>21#include <math.h>22#include <assert.h>2324/* IDEAS:25* Do not fill primes[] with real primes when the range [fr,to] is small,26when fr,to are relatively large. Fill primes[] with odd numbers instead.27[Probably a bad idea, since the primes[] array would become very large.]28* Separate small primes and large primes when sieving. Either the Montgomery29way (i.e., having a large array a multiple of L1 cache size), or just30separate loops for primes <= S and primes > S. The latter primes do not31require an inner loop, since they will touch the sieving array at most once.32* Pre-fill sieving array with an appropriately aligned ...00100100... pattern,33then omit 3 from primes array. (May require similar special handling of 334as we now have for 2.)35* A large SIEVE_LIMIT currently implies very large memory usage, mainly due36to the sieving array in make_primelist, but also because of the primes[]37array. We might want to stage the program, using sieve_region/find_primes38to build primes[]. Make report() a function pointer, as part of achieving39this.40* Store primes[] as two arrays, one array with primes represented as delta41values using just 8 bits (if gaps are too big, store bogus primes!)42and one array with "rem" values. The latter needs 32-bit values.43* A new entry point, mpz_probab_prime_likely_p, would be useful.44* Improve command line syntax and versatility. "primes -f FROM -t TO",45allow either to be omitted for open interval. (But disallow46"primes -c -f FROM" since that would be infinity.) Allow printing a47limited *number* of primes using syntax like "primes -f FROM -n NUMBER".48* When looking for maxgaps, we should not perform any primality testing until49we find possible record gaps. Should speed up the searches tremendously.50*/5152#include "gmp.h"5354struct primes55{56unsigned int prime;57int rem;58};5960struct primes *primes;61unsigned long n_primes;6263void find_primes (unsigned char *, mpz_t, unsigned long, mpz_t);64void sieve_region (unsigned char *, mpz_t, unsigned long);65void make_primelist (unsigned long);6667int flag_print = 1;68int flag_count = 0;69int flag_maxgap = 0;70unsigned long maxgap = 0;71unsigned long total_primes = 0;7273void74report (mpz_t prime)75{76total_primes += 1;77if (flag_print)78{79mpz_out_str (stdout, 10, prime);80printf ("\n");81}82if (flag_maxgap)83{84static unsigned long prev_prime_low = 0;85unsigned long gap;86if (prev_prime_low != 0)87{88gap = mpz_get_ui (prime) - prev_prime_low;89if (maxgap < gap)90maxgap = gap;91}92prev_prime_low = mpz_get_ui (prime);93}94}9596int97main (int argc, char *argv[])98{99char *progname = argv[0];100mpz_t fr, to;101mpz_t fr2, to2;102unsigned long sieve_lim;103unsigned long est_n_primes;104unsigned char *s;105mpz_t tmp;106mpz_t siev_sqr_lim;107108while (argc != 1)109{110if (strcmp (argv[1], "-c") == 0)111{112flag_count = 1;113argv++;114argc--;115}116else if (strcmp (argv[1], "-p") == 0)117{118flag_print = 2;119argv++;120argc--;121}122else if (strcmp (argv[1], "-g") == 0)123{124flag_maxgap = 1;125argv++;126argc--;127}128else129break;130}131132if (flag_count || flag_maxgap)133flag_print--; /* clear unless an explicit -p */134135mpz_init (fr);136mpz_init (to);137mpz_init (fr2);138mpz_init (to2);139140if (argc == 3)141{142mpz_set_str (fr, argv[1], 0);143if (argv[2][0] == '+')144{145mpz_set_str (to, argv[2] + 1, 0);146mpz_add (to, to, fr);147}148else149mpz_set_str (to, argv[2], 0);150}151else if (argc == 2)152{153mpz_set_ui (fr, 0);154mpz_set_str (to, argv[1], 0);155}156else157{158fprintf (stderr, "usage: %s [-c] [-p] [-g] [from [+]]to\n", progname);159exit (1);160}161162mpz_set (fr2, fr);163if (mpz_cmp_ui (fr2, 3) < 0)164{165mpz_set_ui (fr2, 2);166report (fr2);167mpz_set_ui (fr2, 3);168}169mpz_setbit (fr2, 0); /* make odd */170mpz_sub_ui (to2, to, 1);171mpz_setbit (to2, 0); /* make odd */172173mpz_init (tmp);174mpz_init (siev_sqr_lim);175176mpz_sqrt (tmp, to2);177#define SIEVE_LIMIT 10000000178if (mpz_cmp_ui (tmp, SIEVE_LIMIT) < 0)179{180sieve_lim = mpz_get_ui (tmp);181}182else183{184sieve_lim = SIEVE_LIMIT;185mpz_sub (tmp, to2, fr2);186if (mpz_cmp_ui (tmp, sieve_lim) < 0)187sieve_lim = mpz_get_ui (tmp); /* limit sieving for small ranges */188}189mpz_set_ui (siev_sqr_lim, sieve_lim + 1);190mpz_mul_ui (siev_sqr_lim, siev_sqr_lim, sieve_lim + 1);191192est_n_primes = (size_t) (sieve_lim / log((double) sieve_lim) * 1.13) + 10;193primes = malloc (est_n_primes * sizeof primes[0]);194make_primelist (sieve_lim);195assert (est_n_primes >= n_primes);196197#if DEBUG198printf ("sieve_lim = %lu\n", sieve_lim);199printf ("n_primes = %lu (3..%u)\n",200n_primes, primes[n_primes - 1].prime);201#endif202203#define S (1 << 15) /* FIXME: Figure out L1 cache size */204s = malloc (S/2);205while (mpz_cmp (fr2, to2) <= 0)206{207unsigned long rsize;208rsize = S;209mpz_add_ui (tmp, fr2, rsize);210if (mpz_cmp (tmp, to2) > 0)211{212mpz_sub (tmp, to2, fr2);213rsize = mpz_get_ui (tmp) + 2;214}215#if DEBUG216printf ("Sieving region ["); mpz_out_str (stdout, 10, fr2);217printf (","); mpz_add_ui (tmp, fr2, rsize - 2);218mpz_out_str (stdout, 10, tmp); printf ("]\n");219#endif220sieve_region (s, fr2, rsize);221find_primes (s, fr2, rsize / 2, siev_sqr_lim);222223mpz_add_ui (fr2, fr2, S);224}225free (s);226227if (flag_count)228printf ("Pi(interval) = %lu\n", total_primes);229230if (flag_maxgap)231printf ("max gap: %lu\n", maxgap);232233return 0;234}235236/* Find primes in region [fr,fr+rsize). Requires that fr is odd and that237rsize is even. The sieving array s should be aligned for "long int" and238have rsize/2 entries, rounded up to the nearest multiple of "long int". */239void240sieve_region (unsigned char *s, mpz_t fr, unsigned long rsize)241{242unsigned long ssize = rsize / 2;243unsigned long start, start2, prime;244unsigned long i;245mpz_t tmp;246247mpz_init (tmp);248249#if 0250/* initialize sieving array */251for (ii = 0; ii < (ssize + sizeof (long) - 1) / sizeof (long); ii++)252((long *) s) [ii] = ~0L;253#else254{255long k;256long *se = (long *) (s + ((ssize + sizeof (long) - 1) & -sizeof (long)));257for (k = -((ssize + sizeof (long) - 1) / sizeof (long)); k < 0; k++)258se[k] = ~0L;259}260#endif261262for (i = 0; i < n_primes; i++)263{264prime = primes[i].prime;265266if (primes[i].rem >= 0)267{268start2 = primes[i].rem;269}270else271{272mpz_set_ui (tmp, prime);273mpz_mul_ui (tmp, tmp, prime);274if (mpz_cmp (fr, tmp) <= 0)275{276mpz_sub (tmp, tmp, fr);277if (mpz_cmp_ui (tmp, 2 * ssize) > 0)278break; /* avoid overflow at next line, also speedup */279start = mpz_get_ui (tmp);280}281else282{283start = (prime - mpz_tdiv_ui (fr, prime)) % prime;284if (start % 2 != 0)285start += prime; /* adjust if even divisible */286}287start2 = start / 2;288}289290#if 0291for (ii = start2; ii < ssize; ii += prime)292s[ii] = 0;293primes[i].rem = ii - ssize;294#else295{296long k;297unsigned char *se = s + ssize; /* point just beyond sieving range */298for (k = start2 - ssize; k < 0; k += prime)299se[k] = 0;300primes[i].rem = k;301}302#endif303}304mpz_clear (tmp);305}306307/* Find primes in region [fr,fr+rsize), using the previously sieved s[]. */308void309find_primes (unsigned char *s, mpz_t fr, unsigned long ssize,310mpz_t siev_sqr_lim)311{312unsigned long j, ij;313mpz_t tmp;314315mpz_init (tmp);316for (j = 0; j < (ssize + sizeof (long) - 1) / sizeof (long); j++)317{318if (((long *) s) [j] != 0)319{320for (ij = 0; ij < sizeof (long); ij++)321{322if (s[j * sizeof (long) + ij] != 0)323{324if (j * sizeof (long) + ij >= ssize)325goto out;326mpz_add_ui (tmp, fr, (j * sizeof (long) + ij) * 2);327if (mpz_cmp (tmp, siev_sqr_lim) < 0 ||328mpz_probab_prime_p (tmp, 10))329report (tmp);330}331}332}333}334out:335mpz_clear (tmp);336}337338/* Generate a list of primes and store in the global array primes[]. */339void340make_primelist (unsigned long maxprime)341{342#if 1343unsigned char *s;344unsigned long ssize = maxprime / 2;345unsigned long i, ii, j;346347s = malloc (ssize);348memset (s, ~0, ssize);349for (i = 3; ; i += 2)350{351unsigned long isqr = i * i;352if (isqr >= maxprime)353break;354if (s[i * i / 2 - 1] == 0)355continue; /* only sieve with primes */356for (ii = i * i / 2 - 1; ii < ssize; ii += i)357s[ii] = 0;358}359n_primes = 0;360for (j = 0; j < ssize; j++)361{362if (s[j] != 0)363{364primes[n_primes].prime = j * 2 + 3;365primes[n_primes].rem = -1;366n_primes++;367}368}369/* FIXME: This should not be needed if fencepost errors were fixed... */370if (primes[n_primes - 1].prime > maxprime)371n_primes--;372free (s);373#else374unsigned long i;375n_primes = 0;376for (i = 3; i <= maxprime; i += 2)377{378if (i < 7 || (i % 3 != 0 && i % 5 != 0 && i % 7 != 0))379{380primes[n_primes].prime = i;381primes[n_primes].rem = -1;382n_primes++;383}384}385#endif386}387388389