/src/gmp-6.2.1/nextprime.c
Line | Count | Source (jump to first uncovered line) |
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 |
60 | | gmp_nextprime (gmp_primesieve_t *ps) |
61 | 0 | { |
62 | 0 | unsigned long p, d, pi; |
63 | 0 | unsigned char *sp; |
64 | 0 | static unsigned char addtab[] = |
65 | 0 | { 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 | 0 | 2,4,6,2,6,4,2,4,2,10,2,10 }; |
67 | 0 | unsigned char *addp = addtab; |
68 | 0 | 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 | 0 | d = ps->d; |
73 | 0 | sp = ps->s + d; |
74 | 0 | while (*sp != 0) |
75 | 0 | sp++; |
76 | 0 | if (sp != ps->s + SIEVESIZE) |
77 | 0 | { |
78 | 0 | d = sp - ps->s; |
79 | 0 | ps->d = d + 1; |
80 | 0 | return ps->s0 + 2 * d; |
81 | 0 | } |
82 | | |
83 | | /* Handle the number 2 separately. */ |
84 | 0 | if (ps->s0 < 3) |
85 | 0 | { |
86 | 0 | ps->s0 = 3 - 2 * SIEVESIZE; /* Tricky */ |
87 | 0 | return 2; |
88 | 0 | } |
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 | 0 | memset (ps->s, 0, SIEVESIZE); |
97 | 0 | #endif |
98 | |
|
99 | 0 | ps->s0 += 2 * SIEVESIZE; |
100 | | |
101 | | /* Update sqrt_s0 as needed. */ |
102 | 0 | while ((ps->sqrt_s0 + 1) * (ps->sqrt_s0 + 1) <= ps->s0 + 2 * SIEVESIZE - 1) |
103 | 0 | ps->sqrt_s0++; |
104 | |
|
105 | 0 | pi = ((ps->s0 + 3) / 2) % 3; |
106 | 0 | if (pi > 0) |
107 | 0 | pi = 3 - pi; |
108 | 0 | if (ps->s0 + 2 * pi <= 3) |
109 | 0 | pi += 3; |
110 | 0 | sp = ps->s + pi; |
111 | 0 | while (sp < ps->s + SIEVESIZE) |
112 | 0 | { |
113 | 0 | *sp = 1, sp += 3; |
114 | 0 | } |
115 | |
|
116 | 0 | pi = ((ps->s0 + 5) / 2) % 5; |
117 | 0 | if (pi > 0) |
118 | 0 | pi = 5 - pi; |
119 | 0 | if (ps->s0 + 2 * pi <= 5) |
120 | 0 | pi += 5; |
121 | 0 | sp = ps->s + pi; |
122 | 0 | while (sp < ps->s + SIEVESIZE) |
123 | 0 | { |
124 | 0 | *sp = 1, sp += 5; |
125 | 0 | } |
126 | |
|
127 | 0 | pi = ((ps->s0 + 7) / 2) % 7; |
128 | 0 | if (pi > 0) |
129 | 0 | pi = 7 - pi; |
130 | 0 | if (ps->s0 + 2 * pi <= 7) |
131 | 0 | pi += 7; |
132 | 0 | sp = ps->s + pi; |
133 | 0 | while (sp < ps->s + SIEVESIZE) |
134 | 0 | { |
135 | 0 | *sp = 1, sp += 7; |
136 | 0 | } |
137 | |
|
138 | 0 | p = 11; |
139 | 0 | ai = 0; |
140 | 0 | while (p <= ps->sqrt_s0) |
141 | 0 | { |
142 | 0 | pi = ((ps->s0 + p) / 2) % p; |
143 | 0 | if (pi > 0) |
144 | 0 | pi = p - pi; |
145 | 0 | if (ps->s0 + 2 * pi <= p) |
146 | 0 | pi += p; |
147 | 0 | sp = ps->s + pi; |
148 | 0 | while (sp < ps->s + SIEVESIZE) |
149 | 0 | { |
150 | 0 | *sp = 1, sp += p; |
151 | 0 | } |
152 | 0 | p += addp[ai]; |
153 | 0 | ai = (ai + 1) % 48; |
154 | 0 | } |
155 | 0 | ps->d = 0; |
156 | 0 | return gmp_nextprime (ps); |
157 | 0 | } |
158 | | |
159 | | void |
160 | | gmp_init_primesieve (gmp_primesieve_t *ps) |
161 | 0 | { |
162 | 0 | ps->s0 = 0; |
163 | 0 | ps->sqrt_s0 = 0; |
164 | 0 | ps->d = SIEVESIZE; |
165 | 0 | ps->s[SIEVESIZE] = 0; /* sentinel */ |
166 | 0 | } |