Home | History | Annotate | Line # | Download | only in demos
      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.1.2  mrg Copyright 2001, 2002, 2006, 2012 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.1.3  mrg this program.  If not, see https://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.1.2  mrg void find_primes (unsigned char *, mpz_t, unsigned long, mpz_t);
     65  1.1.1.2  mrg void sieve_region (unsigned char *, mpz_t, unsigned long);
     66  1.1.1.2  mrg void make_primelist (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