blob: 84b3b51173914bb9f57725479eac158b4c2587b9 [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/*
2Copyright 2018-2019 Free Software Foundation, Inc.
3
4This file is part of the GNU MP Library test suite.
5
6The GNU MP Library test suite is free software; you can redistribute it
7and/or modify it under the terms of the GNU General Public License as
8published by the Free Software Foundation; either version 3 of the License,
9or (at your option) any later version.
10
11The GNU MP Library test suite is distributed in the hope that it will be
12useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14Public License for more details.
15
16You should have received a copy of the GNU General Public License along with
17the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
18
19/* Usage:
20
21 ./primes [p|c] [n0] <nMax>
22
23 Checks mpz_probab_prime_p(n, r) exhaustively, starting from n=n0
24 up to nMax.
25 If n0 * n0 > nMax, the intervall is sieved piecewise, else the
26 full intervall [0..nMax] is sieved at once.
27 With the parameter "p" (or nothing), tests all numbers. With "c"
28 only composites are tested.
29
30 ./primes n [n0] <nMax>
31
32 Checks mpz_nextprime() exhaustively, starting from n=n0 up to
33 nMax.
34
35 WARNING: The full intervall [0..nMax] is sieved at once, even if
36 only a piece is needed. This may require a lot of memory!
37
38 */
39
40#include <stdlib.h>
41#include <stdio.h>
42#include "gmp-impl.h"
43#include "longlong.h"
44#include "tests.h"
45#define STOP(x) return (x)
46/* #define STOP(x) x */
47#define REPS 10
48/* #define TRACE(x,n) if ((n)>1) {x;} */
49#define TRACE(x,n)
50
51/* The full primesieve.c is included, just for block_resieve, that
52 is not exported ... */
53#undef gmp_primesieve
54#include "../../primesieve.c"
55
56#ifndef BLOCK_SIZE
57#define BLOCK_SIZE 2048
58#endif
59
60/*********************************************************/
61/* Section sieve: sieving functions and tools for primes */
62/*********************************************************/
63
64static mp_size_t
65primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
66
67/*************************************************************/
68/* Section macros: common macros, for swing/fac/bin (&sieve) */
69/*************************************************************/
70
71#define LOOP_ON_SIEVE_CONTINUE(prime,end,sieve) \
72 __max_i = (end); \
73 \
74 do { \
75 ++__i; \
76 if (((sieve)[__index] & __mask) == 0) \
77 { \
78 mp_limb_t prime; \
79 prime = id_to_n(__i)
80
81#define LOOP_ON_SIEVE_BEGIN(prime,start,end,off,sieve) \
82 do { \
83 mp_limb_t __mask, __index, __max_i, __i; \
84 \
85 __i = (start)-(off); \
86 __index = __i / GMP_LIMB_BITS; \
87 __mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS); \
88 __i += (off); \
89 \
90 LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)
91
92#define LOOP_ON_SIEVE_STOP \
93 } \
94 __mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1); \
95 __index += __mask & 1; \
96 } while (__i <= __max_i)
97
98#define LOOP_ON_SIEVE_END \
99 LOOP_ON_SIEVE_STOP; \
100 } while (0)
101
102mpz_t g;
103
104int something_wrong (mpz_t er, int exp)
105{
106 fprintf (stderr, "value = %lu , expected = %i\n", mpz_get_ui (er), exp);
107 return -1;
108}
109
110int
111check_pprime (unsigned long begin, unsigned long end, int composites)
112{
113 begin = (begin / 6U) * 6U;
114 for (;(begin < 2) & (begin <= end); ++begin)
115 {
116 *(g->_mp_d) = begin;
117 TRACE(printf ("-%li ", begin),1);
118 if (mpz_probab_prime_p (g, REPS))
119 STOP (something_wrong (g, 0));
120 }
121 for (;(begin < 4) & (begin <= end); ++begin)
122 {
123 *(g->_mp_d) = begin;
124 TRACE(printf ("+%li ", begin),2);
125 if (!composites && !mpz_probab_prime_p (g, REPS))
126 STOP (something_wrong (g, 1));
127 }
128 if (end > 4) {
129 if ((end > 10000) && (begin > end / begin))
130 {
131 mp_limb_t *sieve, *primes;
132 mp_size_t size_s, size_p, off;
133 unsigned long start;
134
135 mpz_set_ui (g, end);
136 mpz_sqrt (g, g);
137 start = mpz_get_ui (g) + GMP_LIMB_BITS;
138 size_p = primesieve_size (start);
139
140 primes = __GMP_ALLOCATE_FUNC_LIMBS (size_p);
141 gmp_primesieve (primes, start);
142
143 size_s = BLOCK_SIZE * 2;
144 sieve = __GMP_ALLOCATE_FUNC_LIMBS (size_s);
145 off = n_to_bit(begin) + (begin % 3 == 0);
146
147 do {
148 TRACE (printf ("off =%li\n", off),3);
149 block_resieve (sieve, BLOCK_SIZE, off, primes);
150 TRACE (printf ("LOOP =%li - %li\n", id_to_n (off+1), id_to_n (off + BLOCK_SIZE * GMP_LIMB_BITS)),3);
151 LOOP_ON_SIEVE_BEGIN (prime, off, off + BLOCK_SIZE * GMP_LIMB_BITS - 1,
152 off, sieve);
153
154 do {
155 *(g->_mp_d) = begin;
156 TRACE(printf ("-%li ", begin),1);
157 if (mpz_probab_prime_p (g, REPS))
158 STOP (something_wrong (g, 0));
159 if ((begin & 0xff) == 0)
160 {
161 spinner();
162 if ((begin & 0xfffffff) == 0)
163 printf ("%li (0x%lx)\n", begin, begin);
164 }
165 } while (++begin < prime);
166
167 *(g->_mp_d) = begin;
168 TRACE(printf ("+%li ", begin),2);
169 if (!composites && ! mpz_probab_prime_p (g, REPS))
170 STOP (something_wrong (g, 1));
171 ++begin;
172
173 LOOP_ON_SIEVE_END;
174 off += BLOCK_SIZE * GMP_LIMB_BITS;
175 } while (begin < end);
176
177 __GMP_FREE_FUNC_LIMBS (sieve, size_s);
178 __GMP_FREE_FUNC_LIMBS (primes, size_p);
179 }
180 else
181 {
182 mp_limb_t *sieve;
183 mp_size_t size;
184 unsigned long start;
185
186 size = primesieve_size (end);
187
188 sieve = __GMP_ALLOCATE_FUNC_LIMBS (size);
189 gmp_primesieve (sieve, end);
190 start = MAX (begin, 5) | 1;
191 LOOP_ON_SIEVE_BEGIN (prime, n_to_bit(start) + (start % 3 == 0),
192 n_to_bit (end), 0, sieve);
193
194 do {
195 *(g->_mp_d) = begin;
196 TRACE(printf ("-%li ", begin),1);
197 if (mpz_probab_prime_p (g, REPS))
198 STOP (something_wrong (g, 0));
199 if ((begin & 0xff) == 0)
200 {
201 spinner();
202 if ((begin & 0xfffffff) == 0)
203 printf ("%li (0x%lx)\n", begin, begin);
204 }
205 } while (++begin < prime);
206
207 *(g->_mp_d) = begin;
208 TRACE(printf ("+%li ", begin),2);
209 if (!composites && ! mpz_probab_prime_p (g, REPS))
210 STOP (something_wrong (g, 1));
211 ++begin;
212
213 LOOP_ON_SIEVE_END;
214
215 __GMP_FREE_FUNC_LIMBS (sieve, size);
216 }
217 }
218
219 for (;begin < end; ++begin)
220 {
221 *(g->_mp_d) = begin;
222 TRACE(printf ("-%li ", begin),1);
223 if (mpz_probab_prime_p (g, REPS))
224 STOP (something_wrong (g, 0));
225 }
226
227 gmp_printf ("%Zd\n", g);
228 return 0;
229}
230
231int
232check_nprime (unsigned long begin, unsigned long end)
233{
234 if (begin < 2)
235 {
236 *(g->_mp_d) = begin;
237 TRACE(printf ("%li ", begin),1);
238 mpz_nextprime (g, g);
239 if (mpz_cmp_ui (g, 2) != 0)
240 STOP (something_wrong (g, -1));
241 begin = mpz_get_ui (g);
242 }
243 if (begin < 3)
244 {
245 *(g->_mp_d) = begin;
246 TRACE(printf ("%li ", begin),1);
247 mpz_nextprime (g, g);
248 if (mpz_cmp_ui (g, 3) != 0)
249 STOP (something_wrong (g, -1));
250 begin = mpz_get_ui (g);
251 }
252 if (end > 4)
253 {
254 mp_limb_t *sieve;
255 mp_size_t size;
256 unsigned long start;
257
258 size = primesieve_size (end);
259
260 sieve = __GMP_ALLOCATE_FUNC_LIMBS (size);
261 gmp_primesieve (sieve, end);
262 start = MAX (begin, 5) | 1;
263 *(g->_mp_d) = begin;
264 LOOP_ON_SIEVE_BEGIN (prime, n_to_bit(start) + (start % 3 == 0),
265 n_to_bit (end), 0, sieve);
266
267 mpz_nextprime (g, g);
268 if (mpz_cmp_ui (g, prime) != 0)
269 STOP (something_wrong (g, -1));
270
271 if (prime - start > 200)
272 {
273 start = prime;
274 spinner();
275 if (prime - begin > 0xfffffff)
276 {
277 begin = prime;
278 printf ("%li (0x%lx)\n", begin, begin);
279 }
280 }
281
282 LOOP_ON_SIEVE_END;
283
284 __GMP_FREE_FUNC_LIMBS (sieve, size);
285 }
286
287 if (mpz_cmp_ui (g, end) < 0)
288 {
289 mpz_nextprime (g, g);
290 if (mpz_cmp_ui (g, end) <= 0)
291 STOP (something_wrong (g, -1));
292 }
293
294 gmp_printf ("%Zd\n", g);
295 return 0;
296}
297
298int
299main (int argc, char **argv)
300{
301 int ret, mode = 0;
302 unsigned long begin = 0, end = 0;
303
304 for (;argc > 1;--argc,++argv)
305 switch (*argv[1]) {
306 case 'p':
307 mode = 0;
308 break;
309 case 'c':
310 mode = 2;
311 break;
312 case 'n':
313 mode = 1;
314 break;
315 default:
316 begin = end;
317 end = atol (argv[1]);
318 }
319
320 if (begin >= end)
321 {
322 fprintf (stderr, "usage: primes [n|p|c] [n0] <nMax>\n");
323 exit (1);
324 }
325
326 mpz_init_set_ui (g, ULONG_MAX);
327
328 switch (mode) {
329 case 1:
330 ret = check_nprime (begin, end);
331 break;
332 default:
333 ret = check_pprime (begin, end, mode);
334 }
335
336 mpz_clear (g);
337
338 if (ret == 0)
339 printf ("Prime tests checked in [%lu - %lu] [0x%lx - 0x%lx].\n", begin, end, begin, end);
340 return ret;
341}