github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/demos/primes.c (about)

     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  }