Austin Schuh | dace2a6 | 2020-08-18 10:56:48 -0700 | [diff] [blame] | 1 | /* |
| 2 | Copyright 2018-2019 Free Software Foundation, Inc. |
| 3 | |
| 4 | This file is part of the GNU MP Library test suite. |
| 5 | |
| 6 | The GNU MP Library test suite is free software; you can redistribute it |
| 7 | and/or modify it under the terms of the GNU General Public License as |
| 8 | published by the Free Software Foundation; either version 3 of the License, |
| 9 | or (at your option) any later version. |
| 10 | |
| 11 | The GNU MP Library test suite is distributed in the hope that it will be |
| 12 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
| 14 | Public License for more details. |
| 15 | |
| 16 | You should have received a copy of the GNU General Public License along with |
| 17 | the 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 | |
| 64 | static mp_size_t |
| 65 | primesieve_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 | |
| 102 | mpz_t g; |
| 103 | |
| 104 | int 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 | |
| 110 | int |
| 111 | check_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 | |
| 231 | int |
| 232 | check_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 | |
| 298 | int |
| 299 | main (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 | } |