~ubuntu-branches/ubuntu/quantal/gclcvs/quantal

« back to all changes in this revision

Viewing changes to gmp3/demos/primes.c

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-06-24 15:13:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040624151346-xh0xaaktyyp7aorc
Tags: 2.7.0-26
C_GC_OFFSET is 2 on m68k-linux

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 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., 59 Temple
 
18
Place - Suite 330, Boston, MA 02111-1307, 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
  signed int rem;
 
60
};
 
61
 
 
62
struct primes *primes;
 
63
unsigned long n_primes;
 
64
 
 
65
void find_primes (unsigned char *, mpz_t, unsigned long, mpz_t);
 
66
void sieve_region (unsigned char *, mpz_t, unsigned long);
 
67
void make_primelist (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
    signed 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
        signed 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
}