| /* |
| Copyright 2018-2019 Free Software Foundation, Inc. |
| |
| This file is part of the GNU MP Library test suite. |
| |
| The GNU MP Library test suite is free software; you can redistribute it |
| and/or modify it under the terms of the GNU General Public License as |
| published by the Free Software Foundation; either version 3 of the License, |
| or (at your option) any later version. |
| |
| The GNU MP Library test suite is distributed in the hope that it will be |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
| Public License for more details. |
| |
| You should have received a copy of the GNU General Public License along with |
| the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ |
| |
| /* Usage: |
| |
| ./primes [p|c] [n0] <nMax> |
| |
| Checks mpz_probab_prime_p(n, r) exhaustively, starting from n=n0 |
| up to nMax. |
| If n0 * n0 > nMax, the intervall is sieved piecewise, else the |
| full intervall [0..nMax] is sieved at once. |
| With the parameter "p" (or nothing), tests all numbers. With "c" |
| only composites are tested. |
| |
| ./primes n [n0] <nMax> |
| |
| Checks mpz_nextprime() exhaustively, starting from n=n0 up to |
| nMax. |
| |
| WARNING: The full intervall [0..nMax] is sieved at once, even if |
| only a piece is needed. This may require a lot of memory! |
| |
| */ |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include "gmp-impl.h" |
| #include "longlong.h" |
| #include "tests.h" |
| #define STOP(x) return (x) |
| /* #define STOP(x) x */ |
| #define REPS 10 |
| /* #define TRACE(x,n) if ((n)>1) {x;} */ |
| #define TRACE(x,n) |
| |
| /* The full primesieve.c is included, just for block_resieve, that |
| is not exported ... */ |
| #undef gmp_primesieve |
| #include "../../primesieve.c" |
| |
| #ifndef BLOCK_SIZE |
| #define BLOCK_SIZE 2048 |
| #endif |
| |
| /*********************************************************/ |
| /* Section sieve: sieving functions and tools for primes */ |
| /*********************************************************/ |
| |
| static mp_size_t |
| primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; } |
| |
| /*************************************************************/ |
| /* Section macros: common macros, for swing/fac/bin (&sieve) */ |
| /*************************************************************/ |
| |
| #define LOOP_ON_SIEVE_CONTINUE(prime,end,sieve) \ |
| __max_i = (end); \ |
| \ |
| do { \ |
| ++__i; \ |
| if (((sieve)[__index] & __mask) == 0) \ |
| { \ |
| mp_limb_t prime; \ |
| prime = id_to_n(__i) |
| |
| #define LOOP_ON_SIEVE_BEGIN(prime,start,end,off,sieve) \ |
| do { \ |
| mp_limb_t __mask, __index, __max_i, __i; \ |
| \ |
| __i = (start)-(off); \ |
| __index = __i / GMP_LIMB_BITS; \ |
| __mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS); \ |
| __i += (off); \ |
| \ |
| LOOP_ON_SIEVE_CONTINUE(prime,end,sieve) |
| |
| #define LOOP_ON_SIEVE_STOP \ |
| } \ |
| __mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1); \ |
| __index += __mask & 1; \ |
| } while (__i <= __max_i) |
| |
| #define LOOP_ON_SIEVE_END \ |
| LOOP_ON_SIEVE_STOP; \ |
| } while (0) |
| |
| mpz_t g; |
| |
| int something_wrong (mpz_t er, int exp) |
| { |
| fprintf (stderr, "value = %lu , expected = %i\n", mpz_get_ui (er), exp); |
| return -1; |
| } |
| |
| int |
| check_pprime (unsigned long begin, unsigned long end, int composites) |
| { |
| begin = (begin / 6U) * 6U; |
| for (;(begin < 2) & (begin <= end); ++begin) |
| { |
| *(g->_mp_d) = begin; |
| TRACE(printf ("-%li ", begin),1); |
| if (mpz_probab_prime_p (g, REPS)) |
| STOP (something_wrong (g, 0)); |
| } |
| for (;(begin < 4) & (begin <= end); ++begin) |
| { |
| *(g->_mp_d) = begin; |
| TRACE(printf ("+%li ", begin),2); |
| if (!composites && !mpz_probab_prime_p (g, REPS)) |
| STOP (something_wrong (g, 1)); |
| } |
| if (end > 4) { |
| if ((end > 10000) && (begin > end / begin)) |
| { |
| mp_limb_t *sieve, *primes; |
| mp_size_t size_s, size_p, off; |
| unsigned long start; |
| |
| mpz_set_ui (g, end); |
| mpz_sqrt (g, g); |
| start = mpz_get_ui (g) + GMP_LIMB_BITS; |
| size_p = primesieve_size (start); |
| |
| primes = __GMP_ALLOCATE_FUNC_LIMBS (size_p); |
| gmp_primesieve (primes, start); |
| |
| size_s = BLOCK_SIZE * 2; |
| sieve = __GMP_ALLOCATE_FUNC_LIMBS (size_s); |
| off = n_to_bit(begin) + (begin % 3 == 0); |
| |
| do { |
| TRACE (printf ("off =%li\n", off),3); |
| block_resieve (sieve, BLOCK_SIZE, off, primes); |
| TRACE (printf ("LOOP =%li - %li\n", id_to_n (off+1), id_to_n (off + BLOCK_SIZE * GMP_LIMB_BITS)),3); |
| LOOP_ON_SIEVE_BEGIN (prime, off, off + BLOCK_SIZE * GMP_LIMB_BITS - 1, |
| off, sieve); |
| |
| do { |
| *(g->_mp_d) = begin; |
| TRACE(printf ("-%li ", begin),1); |
| if (mpz_probab_prime_p (g, REPS)) |
| STOP (something_wrong (g, 0)); |
| if ((begin & 0xff) == 0) |
| { |
| spinner(); |
| if ((begin & 0xfffffff) == 0) |
| printf ("%li (0x%lx)\n", begin, begin); |
| } |
| } while (++begin < prime); |
| |
| *(g->_mp_d) = begin; |
| TRACE(printf ("+%li ", begin),2); |
| if (!composites && ! mpz_probab_prime_p (g, REPS)) |
| STOP (something_wrong (g, 1)); |
| ++begin; |
| |
| LOOP_ON_SIEVE_END; |
| off += BLOCK_SIZE * GMP_LIMB_BITS; |
| } while (begin < end); |
| |
| __GMP_FREE_FUNC_LIMBS (sieve, size_s); |
| __GMP_FREE_FUNC_LIMBS (primes, size_p); |
| } |
| else |
| { |
| mp_limb_t *sieve; |
| mp_size_t size; |
| unsigned long start; |
| |
| size = primesieve_size (end); |
| |
| sieve = __GMP_ALLOCATE_FUNC_LIMBS (size); |
| gmp_primesieve (sieve, end); |
| start = MAX (begin, 5) | 1; |
| LOOP_ON_SIEVE_BEGIN (prime, n_to_bit(start) + (start % 3 == 0), |
| n_to_bit (end), 0, sieve); |
| |
| do { |
| *(g->_mp_d) = begin; |
| TRACE(printf ("-%li ", begin),1); |
| if (mpz_probab_prime_p (g, REPS)) |
| STOP (something_wrong (g, 0)); |
| if ((begin & 0xff) == 0) |
| { |
| spinner(); |
| if ((begin & 0xfffffff) == 0) |
| printf ("%li (0x%lx)\n", begin, begin); |
| } |
| } while (++begin < prime); |
| |
| *(g->_mp_d) = begin; |
| TRACE(printf ("+%li ", begin),2); |
| if (!composites && ! mpz_probab_prime_p (g, REPS)) |
| STOP (something_wrong (g, 1)); |
| ++begin; |
| |
| LOOP_ON_SIEVE_END; |
| |
| __GMP_FREE_FUNC_LIMBS (sieve, size); |
| } |
| } |
| |
| for (;begin < end; ++begin) |
| { |
| *(g->_mp_d) = begin; |
| TRACE(printf ("-%li ", begin),1); |
| if (mpz_probab_prime_p (g, REPS)) |
| STOP (something_wrong (g, 0)); |
| } |
| |
| gmp_printf ("%Zd\n", g); |
| return 0; |
| } |
| |
| int |
| check_nprime (unsigned long begin, unsigned long end) |
| { |
| if (begin < 2) |
| { |
| *(g->_mp_d) = begin; |
| TRACE(printf ("%li ", begin),1); |
| mpz_nextprime (g, g); |
| if (mpz_cmp_ui (g, 2) != 0) |
| STOP (something_wrong (g, -1)); |
| begin = mpz_get_ui (g); |
| } |
| if (begin < 3) |
| { |
| *(g->_mp_d) = begin; |
| TRACE(printf ("%li ", begin),1); |
| mpz_nextprime (g, g); |
| if (mpz_cmp_ui (g, 3) != 0) |
| STOP (something_wrong (g, -1)); |
| begin = mpz_get_ui (g); |
| } |
| if (end > 4) |
| { |
| mp_limb_t *sieve; |
| mp_size_t size; |
| unsigned long start; |
| |
| size = primesieve_size (end); |
| |
| sieve = __GMP_ALLOCATE_FUNC_LIMBS (size); |
| gmp_primesieve (sieve, end); |
| start = MAX (begin, 5) | 1; |
| *(g->_mp_d) = begin; |
| LOOP_ON_SIEVE_BEGIN (prime, n_to_bit(start) + (start % 3 == 0), |
| n_to_bit (end), 0, sieve); |
| |
| mpz_nextprime (g, g); |
| if (mpz_cmp_ui (g, prime) != 0) |
| STOP (something_wrong (g, -1)); |
| |
| if (prime - start > 200) |
| { |
| start = prime; |
| spinner(); |
| if (prime - begin > 0xfffffff) |
| { |
| begin = prime; |
| printf ("%li (0x%lx)\n", begin, begin); |
| } |
| } |
| |
| LOOP_ON_SIEVE_END; |
| |
| __GMP_FREE_FUNC_LIMBS (sieve, size); |
| } |
| |
| if (mpz_cmp_ui (g, end) < 0) |
| { |
| mpz_nextprime (g, g); |
| if (mpz_cmp_ui (g, end) <= 0) |
| STOP (something_wrong (g, -1)); |
| } |
| |
| gmp_printf ("%Zd\n", g); |
| return 0; |
| } |
| |
| int |
| main (int argc, char **argv) |
| { |
| int ret, mode = 0; |
| unsigned long begin = 0, end = 0; |
| |
| for (;argc > 1;--argc,++argv) |
| switch (*argv[1]) { |
| case 'p': |
| mode = 0; |
| break; |
| case 'c': |
| mode = 2; |
| break; |
| case 'n': |
| mode = 1; |
| break; |
| default: |
| begin = end; |
| end = atol (argv[1]); |
| } |
| |
| if (begin >= end) |
| { |
| fprintf (stderr, "usage: primes [n|p|c] [n0] <nMax>\n"); |
| exit (1); |
| } |
| |
| mpz_init_set_ui (g, ULONG_MAX); |
| |
| switch (mode) { |
| case 1: |
| ret = check_nprime (begin, end); |
| break; |
| default: |
| ret = check_pprime (begin, end, mode); |
| } |
| |
| mpz_clear (g); |
| |
| if (ret == 0) |
| printf ("Prime tests checked in [%lu - %lu] [0x%lx - 0x%lx].\n", begin, end, begin, end); |
| return ret; |
| } |