primes.c
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:10k
源码类别:

数学计算

开发平台:

Unix_Linux

  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. Copyright 2001, 2002, 2006 Free Software Foundation, Inc.
  5. This program is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free Software
  7. Foundation; either version 3 of the License, or (at your option) any later
  8. version.
  9. This program is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  11. PARTICULAR PURPOSE.  See the GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License along with
  13. this program.  If not, see http://www.gnu.org/licenses/.  */
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <math.h>
  18. #include <assert.h>
  19. /* IDEAS:
  20.  * Do not fill primes[] with real primes when the range [fr,to] is small,
  21.    when fr,to are relatively large.  Fill primes[] with odd numbers instead.
  22.    [Probably a bad idea, since the primes[] array would become very large.]
  23.  * Separate small primes and large primes when sieving.  Either the Montgomery
  24.    way (i.e., having a large array a multiple of L1 cache size), or just
  25.    separate loops for primes <= S and primes > S.  The latter primes do not
  26.    require an inner loop, since they will touch the sieving array at most once.
  27.  * Pre-fill sieving array with an appropriately aligned ...00100100... pattern,
  28.    then omit 3 from primes array.  (May require similar special handling of 3
  29.    as we now have for 2.)
  30.  * A large SIEVE_LIMIT currently implies very large memory usage, mainly due
  31.    to the sieving array in make_primelist, but also because of the primes[]
  32.    array.  We might want to stage the program, using sieve_region/find_primes
  33.    to build primes[].  Make report() a function pointer, as part of achieving
  34.    this.
  35.  * Store primes[] as two arrays, one array with primes represented as delta
  36.    values using just 8 bits (if gaps are too big, store bogus primes!)
  37.    and one array with "rem" values.  The latter needs 32-bit values.
  38.  * A new entry point, mpz_probab_prime_likely_p, would be useful.
  39.  * Improve command line syntax and versatility.  "primes -f FROM -t TO",
  40.    allow either to be omitted for open interval.  (But disallow
  41.    "primes -c -f FROM" since that would be infinity.)  Allow printing a
  42.    limited *number* of primes using syntax like "primes -f FROM -n NUMBER".
  43.  * When looking for maxgaps, we should not perform any primality testing until
  44.    we find possible record gaps.  Should speed up the searches tremendously.
  45.  */
  46. #include "gmp.h"
  47. struct primes
  48. {
  49.   unsigned int prime;
  50.   int rem;
  51. };
  52. struct primes *primes;
  53. unsigned long n_primes;
  54. void find_primes __GMP_PROTO ((unsigned char *, mpz_t, unsigned long, mpz_t));
  55. void sieve_region __GMP_PROTO ((unsigned char *, mpz_t, unsigned long));
  56. void make_primelist __GMP_PROTO ((unsigned long));
  57. int flag_print = 1;
  58. int flag_count = 0;
  59. int flag_maxgap = 0;
  60. unsigned long maxgap = 0;
  61. unsigned long total_primes = 0;
  62. void
  63. report (mpz_t prime)
  64. {
  65.   total_primes += 1;
  66.   if (flag_print)
  67.     {
  68.       mpz_out_str (stdout, 10, prime);
  69.       printf ("n");
  70.     }
  71.   if (flag_maxgap)
  72.     {
  73.       static unsigned long prev_prime_low = 0;
  74.       unsigned long gap;
  75.       if (prev_prime_low != 0)
  76. {
  77.   gap = mpz_get_ui (prime) - prev_prime_low;
  78.   if (maxgap < gap)
  79.     maxgap = gap;
  80. }
  81.       prev_prime_low = mpz_get_ui (prime);
  82.     }
  83. }
  84. int
  85. main (int argc, char *argv[])
  86. {
  87.   char *progname = argv[0];
  88.   mpz_t fr, to;
  89.   mpz_t fr2, to2;
  90.   unsigned long sieve_lim;
  91.   unsigned long est_n_primes;
  92.   unsigned char *s;
  93.   mpz_t tmp;
  94.   mpz_t siev_sqr_lim;
  95.   while (argc != 1)
  96.     {
  97.       if (strcmp (argv[1], "-c") == 0)
  98. {
  99.   flag_count = 1;
  100.   argv++;
  101.   argc--;
  102. }
  103.       else if (strcmp (argv[1], "-p") == 0)
  104. {
  105.   flag_print = 2;
  106.   argv++;
  107.   argc--;
  108. }
  109.       else if (strcmp (argv[1], "-g") == 0)
  110. {
  111.   flag_maxgap = 1;
  112.   argv++;
  113.   argc--;
  114. }
  115.       else
  116. break;
  117.     }
  118.   if (flag_count || flag_maxgap)
  119.     flag_print--; /* clear unless an explicit -p  */
  120.   mpz_init (fr);
  121.   mpz_init (to);
  122.   mpz_init (fr2);
  123.   mpz_init (to2);
  124.   if (argc == 3)
  125.     {
  126.       mpz_set_str (fr, argv[1], 0);
  127.       if (argv[2][0] == '+')
  128. {
  129.   mpz_set_str (to, argv[2] + 1, 0);
  130.   mpz_add (to, to, fr);
  131. }
  132.       else
  133. mpz_set_str (to, argv[2], 0);
  134.     }
  135.   else if (argc == 2)
  136.     {
  137.       mpz_set_ui (fr, 0);
  138.       mpz_set_str (to, argv[1], 0);
  139.     }
  140.   else
  141.     {
  142.       fprintf (stderr, "usage: %s [-c] [-p] [-g] [from [+]]ton", progname);
  143.       exit (1);
  144.     }
  145.   mpz_set (fr2, fr);
  146.   if (mpz_cmp_ui (fr2, 3) < 0)
  147.     {
  148.       mpz_set_ui (fr2, 2);
  149.       report (fr2);
  150.       mpz_set_ui (fr2, 3);
  151.     }
  152.   mpz_setbit (fr2, 0); /* make odd */
  153.   mpz_sub_ui (to2, to, 1);
  154.   mpz_setbit (to2, 0); /* make odd */
  155.   mpz_init (tmp);
  156.   mpz_init (siev_sqr_lim);
  157.   mpz_sqrt (tmp, to2);
  158. #define SIEVE_LIMIT 10000000
  159.   if (mpz_cmp_ui (tmp, SIEVE_LIMIT) < 0)
  160.     {
  161.       sieve_lim = mpz_get_ui (tmp);
  162.     }
  163.   else
  164.     {
  165.       sieve_lim = SIEVE_LIMIT;
  166.       mpz_sub (tmp, to2, fr2);
  167.       if (mpz_cmp_ui (tmp, sieve_lim) < 0)
  168. sieve_lim = mpz_get_ui (tmp); /* limit sieving for small ranges */
  169.     }
  170.   mpz_set_ui (siev_sqr_lim, sieve_lim + 1);
  171.   mpz_mul_ui (siev_sqr_lim, siev_sqr_lim, sieve_lim + 1);
  172.   est_n_primes = (size_t) (sieve_lim / log((double) sieve_lim) * 1.13) + 10;
  173.   primes = malloc (est_n_primes * sizeof primes[0]);
  174.   make_primelist (sieve_lim);
  175.   assert (est_n_primes >= n_primes);
  176. #if DEBUG
  177.   printf ("sieve_lim = %lun", sieve_lim);
  178.   printf ("n_primes = %lu (3..%u)n",
  179.   n_primes, primes[n_primes - 1].prime);
  180. #endif
  181. #define S (1 << 15) /* FIXME: Figure out L1 cache size */
  182.   s = malloc (S/2);
  183.   while (mpz_cmp (fr2, to2) <= 0)
  184.     {
  185.       unsigned long rsize;
  186.       rsize = S;
  187.       mpz_add_ui (tmp, fr2, rsize);
  188.       if (mpz_cmp (tmp, to2) > 0)
  189. {
  190.   mpz_sub (tmp, to2, fr2);
  191.   rsize = mpz_get_ui (tmp) + 2;
  192. }
  193. #if DEBUG
  194.       printf ("Sieving region ["); mpz_out_str (stdout, 10, fr2);
  195.       printf (","); mpz_add_ui (tmp, fr2, rsize - 2);
  196.       mpz_out_str (stdout, 10, tmp); printf ("]n");
  197. #endif
  198.       sieve_region (s, fr2, rsize);
  199.       find_primes (s, fr2, rsize / 2, siev_sqr_lim);
  200.       mpz_add_ui (fr2, fr2, S);
  201.     }
  202.   free (s);
  203.   if (flag_count)
  204.     printf ("Pi(interval) = %lun", total_primes);
  205.   if (flag_maxgap)
  206.     printf ("max gap: %lun", maxgap);
  207.   return 0;
  208. }
  209. /* Find primes in region [fr,fr+rsize).  Requires that fr is odd and that
  210.    rsize is even.  The sieving array s should be aligned for "long int" and
  211.    have rsize/2 entries, rounded up to the nearest multiple of "long int".  */
  212. void
  213. sieve_region (unsigned char *s, mpz_t fr, unsigned long rsize)
  214. {
  215.   unsigned long ssize = rsize / 2;
  216.   unsigned long start, start2, prime;
  217.   unsigned long i;
  218.   mpz_t tmp;
  219.   mpz_init (tmp);
  220. #if 0
  221.   /* initialize sieving array */
  222.   for (ii = 0; ii < (ssize + sizeof (long) - 1) / sizeof (long); ii++)
  223.     ((long *) s) [ii] = ~0L;
  224. #else
  225.   {
  226.     long k;
  227.     long *se = (long *) (s + ((ssize + sizeof (long) - 1) & -sizeof (long)));
  228.     for (k = -((ssize + sizeof (long) - 1) / sizeof (long)); k < 0; k++)
  229.       se[k] = ~0L;
  230.   }
  231. #endif
  232.   for (i = 0; i < n_primes; i++)
  233.     {
  234.       prime = primes[i].prime;
  235.       if (primes[i].rem >= 0)
  236. {
  237.   start2 = primes[i].rem;
  238. }
  239.       else
  240. {
  241.   mpz_set_ui (tmp, prime);
  242.   mpz_mul_ui (tmp, tmp, prime);
  243.   if (mpz_cmp (fr, tmp) <= 0)
  244.     {
  245.       mpz_sub (tmp, tmp, fr);
  246.       if (mpz_cmp_ui (tmp, 2 * ssize) > 0)
  247. break; /* avoid overflow at next line, also speedup */
  248.       start = mpz_get_ui (tmp);
  249.     }
  250.   else
  251.     {
  252.       start = (prime - mpz_tdiv_ui (fr, prime)) % prime;
  253.       if (start % 2 != 0)
  254. start += prime; /* adjust if even divisible */
  255.     }
  256.   start2 = start / 2;
  257. }
  258. #if 0
  259.       for (ii = start2; ii < ssize; ii += prime)
  260. s[ii] = 0;
  261.       primes[i].rem = ii - ssize;
  262. #else
  263.       {
  264. long k;
  265. unsigned char *se = s + ssize; /* point just beyond sieving range */
  266. for (k = start2 - ssize; k < 0; k += prime)
  267.   se[k] = 0;
  268. primes[i].rem = k;
  269.       }
  270. #endif
  271.     }
  272.   mpz_clear (tmp);
  273. }
  274. /* Find primes in region [fr,fr+rsize), using the previously sieved s[].  */
  275. void
  276. find_primes (unsigned char *s, mpz_t  fr, unsigned long ssize,
  277.      mpz_t siev_sqr_lim)
  278. {
  279.   unsigned long j, ij;
  280.   mpz_t tmp;
  281.   mpz_init (tmp);
  282.   for (j = 0; j < (ssize + sizeof (long) - 1) / sizeof (long); j++)
  283.     {
  284.       if (((long *) s) [j] != 0)
  285. {
  286.   for (ij = 0; ij < sizeof (long); ij++)
  287.     {
  288.       if (s[j * sizeof (long) + ij] != 0)
  289. {
  290.   if (j * sizeof (long) + ij >= ssize)
  291.     goto out;
  292.   mpz_add_ui (tmp, fr, (j * sizeof (long) + ij) * 2);
  293.   if (mpz_cmp (tmp, siev_sqr_lim) < 0 ||
  294.       mpz_probab_prime_p (tmp, 10))
  295.     report (tmp);
  296. }
  297.     }
  298. }
  299.     }
  300.  out:
  301.   mpz_clear (tmp);
  302. }
  303. /* Generate a list of primes and store in the global array primes[].  */
  304. void
  305. make_primelist (unsigned long maxprime)
  306. {
  307. #if 1
  308.   unsigned char *s;
  309.   unsigned long ssize = maxprime / 2;
  310.   unsigned long i, ii, j;
  311.   s = malloc (ssize);
  312.   memset (s, ~0, ssize);
  313.   for (i = 3; ; i += 2)
  314.     {
  315.       unsigned long isqr = i * i;
  316.       if (isqr >= maxprime)
  317. break;
  318.       if (s[i * i / 2 - 1] == 0)
  319. continue; /* only sieve with primes */
  320.       for (ii = i * i / 2 - 1; ii < ssize; ii += i)
  321. s[ii] = 0;
  322.     }
  323.   n_primes = 0;
  324.   for (j = 0; j < ssize; j++)
  325.     {
  326.       if (s[j] != 0)
  327. {
  328.   primes[n_primes].prime = j * 2 + 3;
  329.   primes[n_primes].rem = -1;
  330.   n_primes++;
  331. }
  332.     }
  333.   /* FIXME: This should not be needed if fencepost errors were fixed... */
  334.   if (primes[n_primes - 1].prime > maxprime)
  335.     n_primes--;
  336.   free (s);
  337. #else
  338.   unsigned long i;
  339.   n_primes = 0;
  340.   for (i = 3; i <= maxprime; i += 2)
  341.     {
  342.       if (i < 7 || (i % 3 != 0 && i % 5 != 0 && i % 7 != 0))
  343. {
  344.   primes[n_primes].prime = i;
  345.   primes[n_primes].rem = -1;
  346.   n_primes++;
  347. }
  348.     }
  349. #endif
  350. }