/src/libgmp/mpz/nextprime.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* mpz_nextprime(p,t) - compute the next prime > t and store that in p. |
2 | | |
3 | | Copyright 1999-2001, 2008, 2009, 2012, 2020-2022 Free Software |
4 | | Foundation, Inc. |
5 | | |
6 | | Contributed to the GNU project by Niels Möller and Torbjorn Granlund. |
7 | | Improved by Seth Troisi. |
8 | | |
9 | | This file is part of the GNU MP Library. |
10 | | |
11 | | The GNU MP Library is free software; you can redistribute it and/or modify |
12 | | it under the terms of either: |
13 | | |
14 | | * the GNU Lesser General Public License as published by the Free |
15 | | Software Foundation; either version 3 of the License, or (at your |
16 | | option) any later version. |
17 | | |
18 | | or |
19 | | |
20 | | * the GNU General Public License as published by the Free Software |
21 | | Foundation; either version 2 of the License, or (at your option) any |
22 | | later version. |
23 | | |
24 | | or both in parallel, as here. |
25 | | |
26 | | The GNU MP Library is distributed in the hope that it will be useful, but |
27 | | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
28 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
29 | | for more details. |
30 | | |
31 | | You should have received copies of the GNU General Public License and the |
32 | | GNU Lesser General Public License along with the GNU MP Library. If not, |
33 | | see https://www.gnu.org/licenses/. */ |
34 | | |
35 | | #include <string.h> |
36 | | |
37 | | #include "gmp-impl.h" |
38 | | #include "longlong.h" |
39 | | |
40 | | /*********************************************************/ |
41 | | /* Section sieve: sieving functions and tools for primes */ |
42 | | /*********************************************************/ |
43 | | |
44 | | static mp_limb_t |
45 | 2.49k | n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; } |
46 | | |
47 | | static mp_size_t |
48 | 2.49k | primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; } |
49 | | |
50 | | |
51 | | static const unsigned char primegap_small[] = |
52 | | { |
53 | | 2,2,4,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,14,4,6, |
54 | | 2,10,2,6,6,4,6,6,2,10,2,4,2,12,12,4,2,4,6,2,10,6,6,6,2,6,4,2,10,14,4,2, |
55 | | 4,14,6,10,2,4,6,8,6,6,4,6,8,4,8,10,2,10,2,6,4,6,8,4,2,4,12,8,4,8,4,6, |
56 | | 12,2,18,6,10 |
57 | | }; |
58 | | |
59 | 2.02k | #define NUMBER_OF_PRIMES 100 |
60 | | #define LAST_PRIME 557 |
61 | | /* NP_SMALL_LIMIT = prevprime (LAST_PRIME ^ 2) */ |
62 | | #define NP_SMALL_LIMIT 310243 |
63 | | |
64 | | static unsigned long |
65 | 1.24k | calculate_sievelimit(mp_bitcnt_t nbits) { |
66 | 1.24k | unsigned long sieve_limit; |
67 | | |
68 | | /* Estimate a good sieve bound. Based on derivative of |
69 | | * Merten's 3rd theorem * avg gap * cost of mod |
70 | | * vs |
71 | | * Cost of PRP test O(N^2.55) |
72 | | */ |
73 | 1.24k | if (nbits < 12818) |
74 | 1.24k | { |
75 | 1.24k | mpz_t tmp; |
76 | | /* sieve_limit ~= nbits ^ (5/2) / 124 */ |
77 | 1.24k | mpz_init (tmp); |
78 | 1.24k | mpz_ui_pow_ui (tmp, nbits, 5); |
79 | 1.24k | mpz_tdiv_q_ui(tmp, tmp, 124*124); |
80 | | /* tmp < 12818^5/(124*124) < 2^55 < 2^64 */ |
81 | 1.24k | mpz_sqrt (tmp, tmp); |
82 | | |
83 | 1.24k | sieve_limit = mpz_get_ui(tmp); |
84 | 1.24k | mpz_clear (tmp); |
85 | 1.24k | } |
86 | 0 | else |
87 | 0 | { |
88 | | /* Larger threshold is faster but takes (n/ln(n) + n/24) memory. |
89 | | * For 33,000 bits limitting to 150M is ~12% slower than using the |
90 | | * optimal 1.5G sieve_limit. |
91 | | */ |
92 | 0 | sieve_limit = 150000001; |
93 | 0 | } |
94 | | |
95 | 1.24k | ASSERT (1000 < sieve_limit && sieve_limit <= 150000001); |
96 | 1.24k | return sieve_limit; |
97 | 1.24k | } |
98 | | |
99 | | static unsigned |
100 | | findnext_small (unsigned t, short diff) |
101 | 128 | { |
102 | | /* For diff= 2, expect t = 1 if operand was negative. |
103 | | * For diff=-2, expect t >= 3 |
104 | | */ |
105 | 128 | ASSERT (t >= 3 || (diff > 0 && t >= 1)); |
106 | 128 | ASSERT (t < NP_SMALL_LIMIT); |
107 | | |
108 | | /* Start from next candidate (2 or odd) */ |
109 | 128 | t = diff > 0 ? |
110 | 128 | (t + 1) | (t != 1) : |
111 | 128 | ((t - 2) | 1) + (t == 3); |
112 | | |
113 | 128 | for (; ; t += diff) |
114 | 193 | { |
115 | 193 | unsigned prime = 3; |
116 | 1.17k | for (int i = 0; ; prime += primegap_small[i++]) |
117 | 1.37k | { |
118 | 1.37k | unsigned q, r; |
119 | 1.37k | q = t / prime; |
120 | 1.37k | r = t - q * prime; /* r = t % prime; */ |
121 | 1.37k | if (q < prime) |
122 | 128 | return t; |
123 | 1.24k | if (r == 0) |
124 | 65 | break; |
125 | 1.17k | ASSERT (i < NUMBER_OF_PRIMES); |
126 | 1.17k | } |
127 | 193 | } |
128 | 128 | } |
129 | | |
130 | | static int |
131 | | findnext (mpz_ptr p, |
132 | | unsigned long(*negative_mod_ui)(const mpz_t, unsigned long), |
133 | | void(*increment_ui)(mpz_t, const mpz_t, unsigned long)) |
134 | 2.02k | { |
135 | 2.02k | char *composite; |
136 | 2.02k | const unsigned char *primegap; |
137 | 2.02k | unsigned long prime_limit; |
138 | 2.02k | mp_size_t pn; |
139 | 2.02k | mp_bitcnt_t nbits; |
140 | 2.02k | int i, m; |
141 | 2.02k | unsigned odds_in_composite_sieve; |
142 | 2.02k | TMP_DECL; |
143 | | |
144 | 2.02k | TMP_MARK; |
145 | 2.02k | pn = SIZ(p); |
146 | 2.02k | MPN_SIZEINBASE_2EXP(nbits, PTR(p), pn, 1); |
147 | | /* Smaller numbers handled earlier */ |
148 | 2.02k | ASSERT (nbits >= 3); |
149 | | /* Make p odd */ |
150 | 2.02k | PTR(p)[0] |= 1; |
151 | | |
152 | 2.02k | if (nbits / 2 <= NUMBER_OF_PRIMES) |
153 | 778 | { |
154 | 778 | primegap = primegap_small; |
155 | 778 | prime_limit = nbits / 2; |
156 | 778 | } |
157 | 1.24k | else |
158 | 1.24k | { |
159 | 1.24k | unsigned long sieve_limit; |
160 | 1.24k | mp_limb_t *sieve; |
161 | 1.24k | unsigned char *primegap_tmp; |
162 | 1.24k | unsigned long last_prime; |
163 | | |
164 | | /* sieve numbers up to sieve_limit and save prime count */ |
165 | 1.24k | sieve_limit = calculate_sievelimit(nbits); |
166 | 1.24k | sieve = TMP_ALLOC_LIMBS (primesieve_size (sieve_limit)); |
167 | 1.24k | prime_limit = gmp_primesieve(sieve, sieve_limit); |
168 | | |
169 | | /* TODO: Storing (prime - last_prime)/2 would allow this to go |
170 | | up to the gap 304599508537+514=304599509051 . |
171 | | With the current code our limit is 436273009+282=436273291 */ |
172 | 1.24k | ASSERT (sieve_limit < 436273291); |
173 | | /* THINK: Memory used by both sieve and primegap_tmp is kept |
174 | | allocated, but they may overlap if primegap is filled from |
175 | | larger down to smaller primes... |
176 | | */ |
177 | | |
178 | | /* Needed to avoid assignment of read-only location */ |
179 | 1.24k | primegap_tmp = TMP_ALLOC_TYPE (prime_limit, unsigned char); |
180 | 1.24k | primegap = primegap_tmp; |
181 | | |
182 | 1.24k | i = 0; |
183 | 1.24k | last_prime = 3; |
184 | | /* THINK: should we get rid of sieve_limit and use (i < prime_limit)? */ |
185 | 166k | for (mp_limb_t j = 4, *sp = sieve; j < sieve_limit; j += GMP_LIMB_BITS * 3) |
186 | 10.4M | for (mp_limb_t b = j, x = ~ *(sp++); x != 0; b += 3, x >>= 1) |
187 | 10.2M | if (x & 1) |
188 | 3.44M | { |
189 | 3.44M | mp_limb_t prime = b | 1; |
190 | 3.44M | primegap_tmp[i++] = prime - last_prime; |
191 | 3.44M | last_prime = prime; |
192 | 3.44M | } |
193 | | |
194 | | /* Both primesieve and prime_limit ignore the first two primes. */ |
195 | 1.24k | ASSERT(i == prime_limit); |
196 | 1.24k | } |
197 | | |
198 | 2.02k | if (nbits <= 32) |
199 | 166 | odds_in_composite_sieve = 336 / 2; |
200 | 1.86k | else if (nbits <= 64) |
201 | 240 | odds_in_composite_sieve = 1550 / 2; |
202 | 1.62k | else |
203 | | /* Corresponds to a merit 14 prime_gap, which is rare. */ |
204 | 1.62k | odds_in_composite_sieve = 5 * nbits; |
205 | | |
206 | | /* composite[2*i] stores if p+2*i is a known composite */ |
207 | 2.02k | composite = TMP_ALLOC_TYPE (odds_in_composite_sieve, char); |
208 | | |
209 | 2.02k | for (;;) |
210 | 2.02k | { |
211 | 2.02k | unsigned long difference; |
212 | 2.02k | unsigned long incr, prime; |
213 | 2.02k | int primetest; |
214 | | |
215 | 2.02k | memset (composite, 0, odds_in_composite_sieve); |
216 | 2.02k | prime = 3; |
217 | 3.47M | for (i = 0; i < prime_limit; i++) |
218 | 3.47M | { |
219 | | /* Distance to next multiple of prime */ |
220 | 3.47M | m = negative_mod_ui(p, prime); |
221 | | /* Only care about odd multiplies of prime. */ |
222 | 3.47M | if (m & 1) |
223 | 1.73M | m += prime; |
224 | 3.47M | m >>= 1; |
225 | | |
226 | | /* Mark off any composites in sieve */ |
227 | 9.00M | for (; m < odds_in_composite_sieve; m += prime) |
228 | 5.52M | composite[m] = 1; |
229 | 3.47M | prime += primegap[i]; |
230 | 3.47M | } |
231 | | |
232 | 2.02k | difference = 0; |
233 | 182k | for (incr = 0; incr < odds_in_composite_sieve; difference += 2, incr += 1) |
234 | 182k | { |
235 | 182k | if (composite[incr]) |
236 | 160k | continue; |
237 | | |
238 | 22.4k | increment_ui(p, p, difference); |
239 | 22.4k | difference = 0; |
240 | | |
241 | | /* Miller-Rabin test */ |
242 | 22.4k | primetest = mpz_millerrabin (p, 25); |
243 | 22.4k | if (primetest) |
244 | 2.02k | { |
245 | 2.02k | TMP_FREE; |
246 | 2.02k | return primetest; |
247 | 2.02k | } |
248 | 22.4k | } |
249 | | |
250 | | /* Sieve next segment, very rare */ |
251 | 0 | increment_ui(p, p, difference); |
252 | 0 | } |
253 | 2.02k | } |
254 | | |
255 | | void |
256 | | mpz_nextprime (mpz_ptr p, mpz_srcptr n) |
257 | 2.15k | { |
258 | | /* Handle negative and small numbers */ |
259 | 2.15k | if (mpz_cmp_ui (n, NP_SMALL_LIMIT) < 0) |
260 | 128 | { |
261 | 128 | ASSERT (NP_SMALL_LIMIT < UINT_MAX); |
262 | 128 | mpz_set_ui (p, findnext_small (SIZ (n) > 0 ? mpz_get_ui (n) : 1, +2)); |
263 | 128 | return; |
264 | 128 | } |
265 | | |
266 | | /* First odd greater than n */ |
267 | 2.02k | mpz_add_ui (p, n, 1); |
268 | | |
269 | 2.02k | findnext(p, mpz_cdiv_ui, mpz_add_ui); |
270 | 2.02k | } |
271 | | |
272 | | int |
273 | | mpz_prevprime (mpz_ptr p, mpz_srcptr n) |
274 | 0 | { |
275 | | /* Handle negative and small numbers */ |
276 | 0 | if (mpz_cmp_ui (n, 2) <= 0) |
277 | 0 | return 0; |
278 | | |
279 | 0 | if (mpz_cmp_ui (n, NP_SMALL_LIMIT) < 0) |
280 | 0 | { |
281 | 0 | ASSERT (NP_SMALL_LIMIT < UINT_MAX); |
282 | 0 | mpz_set_ui (p, findnext_small (mpz_get_ui (n), -2)); |
283 | 0 | return 2; |
284 | 0 | } |
285 | | |
286 | | /* First odd less than n */ |
287 | 0 | mpz_sub_ui (p, n, 2); |
288 | |
|
289 | 0 | return findnext(p, mpz_tdiv_ui, mpz_sub_ui); |
290 | 0 | } |
291 | | |