xref: /netbsd-src/external/lgpl3/gmp/dist/nextprime.c (revision 72c7faa4dbb41dbb0238d6b4a109da0d4b236dd4)
1 /* gmp_nextprime -- generate small primes reasonably efficiently for internal
2    GMP needs.
3 
4    Contributed to the GNU project by Torbjorn Granlund.  Miscellaneous
5    improvements by Martin Boij.
6 
7    THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
8    SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
9    GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
10 
11 Copyright 2009 Free Software Foundation, Inc.
12 
13 This file is part of the GNU MP Library.
14 
15 The GNU MP Library is free software; you can redistribute it and/or modify
16 it under the terms of either:
17 
18   * the GNU Lesser General Public License as published by the Free
19     Software Foundation; either version 3 of the License, or (at your
20     option) any later version.
21 
22 or
23 
24   * the GNU General Public License as published by the Free Software
25     Foundation; either version 2 of the License, or (at your option) any
26     later version.
27 
28 or both in parallel, as here.
29 
30 The GNU MP Library is distributed in the hope that it will be useful, but
31 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
32 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
33 for more details.
34 
35 You should have received copies of the GNU General Public License and the
36 GNU Lesser General Public License along with the GNU MP Library.  If not,
37 see https://www.gnu.org/licenses/.  */
38 
39 /*
40   Optimisation ideas:
41 
42   1. Unroll the sieving loops.  Should reach 1 write/cycle.  That would be a 2x
43      improvement.
44 
45   2. Separate sieving with primes p < SIEVESIZE and p >= SIEVESIZE.  The latter
46      will need at most one write, and thus not need any inner loop.
47 
48   3. For primes p >= SIEVESIZE, i.e., typically the majority of primes, we
49      perform more than one division per sieving write.  That might dominate the
50      entire run time for the nextprime function.  A incrementally initialised
51      remainder table of Pi(65536) = 6542 16-bit entries could replace that
52      division.
53 */
54 
55 #include "gmp-impl.h"
56 #include <string.h>		/* for memset */
57 
58 
59 unsigned long int
gmp_nextprime(gmp_primesieve_t * ps)60 gmp_nextprime (gmp_primesieve_t *ps)
61 {
62   unsigned long p, d, pi;
63   unsigned char *sp;
64   static unsigned char addtab[] =
65     { 2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,2,4,6,2,6,6,4,
66       2,4,6,2,6,4,2,4,2,10,2,10 };
67   unsigned char *addp = addtab;
68   unsigned long ai;
69 
70   /* Look for already sieved primes.  A sentinel at the end of the sieving
71      area allows us to use a very simple loop here.  */
72   d = ps->d;
73   sp = ps->s + d;
74   while (*sp != 0)
75     sp++;
76   if (sp != ps->s + SIEVESIZE)
77     {
78       d = sp - ps->s;
79       ps->d = d + 1;
80       return ps->s0 + 2 * d;
81     }
82 
83   /* Handle the number 2 separately.  */
84   if (ps->s0 < 3)
85     {
86       ps->s0 = 3 - 2 * SIEVESIZE; /* Tricky */
87       return 2;
88     }
89 
90   /* Exhausted computed primes.  Resieve, then call ourselves recursively.  */
91 
92 #if 0
93   for (sp = ps->s; sp < ps->s + SIEVESIZE; sp++)
94     *sp = 0;
95 #else
96   memset (ps->s, 0, SIEVESIZE);
97 #endif
98 
99   ps->s0 += 2 * SIEVESIZE;
100 
101   /* Update sqrt_s0 as needed.  */
102   while ((ps->sqrt_s0 + 1) * (ps->sqrt_s0 + 1) <= ps->s0 + 2 * SIEVESIZE - 1)
103     ps->sqrt_s0++;
104 
105   pi = ((ps->s0 + 3) / 2) % 3;
106   if (pi > 0)
107     pi = 3 - pi;
108   if (ps->s0 + 2 * pi <= 3)
109     pi += 3;
110   sp = ps->s + pi;
111   while (sp < ps->s + SIEVESIZE)
112     {
113       *sp = 1, sp += 3;
114     }
115 
116   pi = ((ps->s0 + 5) / 2) % 5;
117   if (pi > 0)
118     pi = 5 - pi;
119   if (ps->s0 + 2 * pi <= 5)
120     pi += 5;
121   sp = ps->s + pi;
122   while (sp < ps->s + SIEVESIZE)
123     {
124       *sp = 1, sp += 5;
125     }
126 
127   pi = ((ps->s0 + 7) / 2) % 7;
128   if (pi > 0)
129     pi = 7 - pi;
130   if (ps->s0 + 2 * pi <= 7)
131     pi += 7;
132   sp = ps->s + pi;
133   while (sp < ps->s + SIEVESIZE)
134     {
135       *sp = 1, sp += 7;
136     }
137 
138   p = 11;
139   ai = 0;
140   while (p <= ps->sqrt_s0)
141     {
142       pi = ((ps->s0 + p) / 2) % p;
143       if (pi > 0)
144 	pi = p - pi;
145       if (ps->s0 + 2 * pi <= p)
146 	  pi += p;
147       sp = ps->s + pi;
148       while (sp < ps->s + SIEVESIZE)
149 	{
150 	  *sp = 1, sp += p;
151 	}
152       p += addp[ai];
153       ai = (ai + 1) % 48;
154     }
155   ps->d = 0;
156   return gmp_nextprime (ps);
157 }
158 
159 void
gmp_init_primesieve(gmp_primesieve_t * ps)160 gmp_init_primesieve (gmp_primesieve_t *ps)
161 {
162   ps->s0 = 0;
163   ps->sqrt_s0 = 0;
164   ps->d = SIEVESIZE;
165   ps->s[SIEVESIZE] = 0;		/* sentinel */
166 }
167