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