/* mpz_nextprime(p,t) - compute the next prime > t and store that in p. Copyright 1999-2001, 2008, 2009, 2012, 2020-2022 Free Software Foundation, Inc. Contributed to the GNU project by Niels Möller and Torbjorn Granlund. Improved by Seth Troisi. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of either: * the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. or * the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. or both in parallel, as here. The GNU MP Library 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 copies of the GNU General Public License and the GNU Lesser General Public License along with the GNU MP Library. If not, see https://www.gnu.org/licenses/. */ #include #include "gmp-impl.h" #include "longlong.h" /*********************************************************/ /* Section sieve: sieving functions and tools for primes */ /*********************************************************/ static mp_limb_t n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; } static mp_size_t primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; } static const unsigned char primegap_small[] = { 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, 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, 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, 12,2,18,6,10 }; #define NUMBER_OF_PRIMES 100 #define LAST_PRIME 557 /* NP_SMALL_LIMIT = prevprime (LAST_PRIME ^ 2) */ #define NP_SMALL_LIMIT 310243 static unsigned long calculate_sievelimit(mp_bitcnt_t nbits) { unsigned long sieve_limit; /* Estimate a good sieve bound. Based on derivative of * Merten's 3rd theorem * avg gap * cost of mod * vs * Cost of PRP test O(N^2.55) */ if (nbits < 12818) { mpz_t tmp; /* sieve_limit ~= nbits ^ (5/2) / 124 */ mpz_init (tmp); mpz_ui_pow_ui (tmp, nbits, 5); mpz_tdiv_q_ui(tmp, tmp, 124*124); /* tmp < 12818^5/(124*124) < 2^55 < 2^64 */ mpz_sqrt (tmp, tmp); sieve_limit = mpz_get_ui(tmp); mpz_clear (tmp); } else { /* Larger threshold is faster but takes (n/ln(n) + n/24) memory. * For 33,000 bits limitting to 150M is ~12% slower than using the * optimal 1.5G sieve_limit. */ sieve_limit = 150000001; } ASSERT (1000 < sieve_limit && sieve_limit <= 150000001); return sieve_limit; } static unsigned findnext_small (unsigned t, short diff) { /* For diff= 2, expect t = 1 if operand was negative. * For diff=-2, expect t >= 3 */ ASSERT (t >= 3 || (diff > 0 && t >= 1)); ASSERT (t < NP_SMALL_LIMIT); /* Start from next candidate (2 or odd) */ t = diff > 0 ? (t + 1) | (t != 1) : ((t - 2) | 1) + (t == 3); for (; ; t += diff) { unsigned prime = 3; for (int i = 0; ; prime += primegap_small[i++]) { unsigned q, r; q = t / prime; r = t - q * prime; /* r = t % prime; */ if (q < prime) return t; if (r == 0) break; ASSERT (i < NUMBER_OF_PRIMES); } } } static int findnext (mpz_ptr p, unsigned long(*negative_mod_ui)(const mpz_t, unsigned long), void(*increment_ui)(mpz_t, const mpz_t, unsigned long)) { char *composite; const unsigned char *primegap; unsigned long prime_limit; mp_size_t pn; mp_bitcnt_t nbits; int i, m; unsigned odds_in_composite_sieve; TMP_DECL; TMP_MARK; pn = SIZ(p); MPN_SIZEINBASE_2EXP(nbits, PTR(p), pn, 1); /* Smaller numbers handled earlier */ ASSERT (nbits >= 3); /* Make p odd */ PTR(p)[0] |= 1; if (nbits / 2 <= NUMBER_OF_PRIMES) { primegap = primegap_small; prime_limit = nbits / 2; } else { unsigned long sieve_limit; mp_limb_t *sieve; unsigned char *primegap_tmp; unsigned long last_prime; /* sieve numbers up to sieve_limit and save prime count */ sieve_limit = calculate_sievelimit(nbits); sieve = TMP_ALLOC_LIMBS (primesieve_size (sieve_limit)); prime_limit = gmp_primesieve(sieve, sieve_limit); /* TODO: Storing (prime - last_prime)/2 would allow this to go up to the gap 304599508537+514=304599509051 . With the current code our limit is 436273009+282=436273291 */ ASSERT (sieve_limit < 436273291); /* THINK: Memory used by both sieve and primegap_tmp is kept allocated, but they may overlap if primegap is filled from larger down to smaller primes... */ /* Needed to avoid assignment of read-only location */ primegap_tmp = TMP_ALLOC_TYPE (prime_limit, unsigned char); primegap = primegap_tmp; i = 0; last_prime = 3; /* THINK: should we get rid of sieve_limit and use (i < prime_limit)? */ for (mp_limb_t j = 4, *sp = sieve; j < sieve_limit; j += GMP_LIMB_BITS * 3) for (mp_limb_t b = j, x = ~ *(sp++); x != 0; b += 3, x >>= 1) if (x & 1) { mp_limb_t prime = b | 1; primegap_tmp[i++] = prime - last_prime; last_prime = prime; } /* Both primesieve and prime_limit ignore the first two primes. */ ASSERT(i == prime_limit); } if (nbits <= 32) odds_in_composite_sieve = 336 / 2; else if (nbits <= 64) odds_in_composite_sieve = 1550 / 2; else /* Corresponds to a merit 14 prime_gap, which is rare. */ odds_in_composite_sieve = 5 * nbits; /* composite[2*i] stores if p+2*i is a known composite */ composite = TMP_ALLOC_TYPE (odds_in_composite_sieve, char); for (;;) { unsigned long difference; unsigned long incr, prime; int primetest; memset (composite, 0, odds_in_composite_sieve); prime = 3; for (i = 0; i < prime_limit; i++) { /* Distance to next multiple of prime */ m = negative_mod_ui(p, prime); /* Only care about odd multiplies of prime. */ if (m & 1) m += prime; m >>= 1; /* Mark off any composites in sieve */ for (; m < odds_in_composite_sieve; m += prime) composite[m] = 1; prime += primegap[i]; } difference = 0; for (incr = 0; incr < odds_in_composite_sieve; difference += 2, incr += 1) { if (composite[incr]) continue; increment_ui(p, p, difference); difference = 0; /* Miller-Rabin test */ primetest = mpz_millerrabin (p, 25); if (primetest) { TMP_FREE; return primetest; } } /* Sieve next segment, very rare */ increment_ui(p, p, difference); } } void mpz_nextprime (mpz_ptr p, mpz_srcptr n) { /* Handle negative and small numbers */ if (mpz_cmp_ui (n, NP_SMALL_LIMIT) < 0) { ASSERT (NP_SMALL_LIMIT < UINT_MAX); mpz_set_ui (p, findnext_small (SIZ (n) > 0 ? mpz_get_ui (n) : 1, +2)); return; } /* First odd greater than n */ mpz_add_ui (p, n, 1); findnext(p, mpz_cdiv_ui, mpz_add_ui); } int mpz_prevprime (mpz_ptr p, mpz_srcptr n) { /* Handle negative and small numbers */ if (mpz_cmp_ui (n, 2) <= 0) return 0; if (mpz_cmp_ui (n, NP_SMALL_LIMIT) < 0) { ASSERT (NP_SMALL_LIMIT < UINT_MAX); mpz_set_ui (p, findnext_small (mpz_get_ui (n), -2)); return 2; } /* First odd less than n */ mpz_sub_ui (p, n, 2); return findnext(p, mpz_tdiv_ui, mpz_sub_ui); }