void mpz_nextprime (mpz_ptr p, mpz_srcptr n) { mpz_t tmp; unsigned short *moduli; unsigned long difference; int i; int composite; /* First handle tiny numbers */ if (mpz_cmp_ui (n, 2) < 0) { mpz_set_ui (p, 2); return; } mpz_add_ui (p, n, 1); mpz_setbit (p, 0); if (mpz_cmp_ui (p, 7) <= 0) return; prime_limit = NUMBER_OF_PRIMES - 1; if (mpz_cmp_ui (p, primes[prime_limit]) <= 0) /* Just use first three entries (3,5,7) of table for small numbers */ prime_limit = 3; if (prime_limit) { /* Compute residues modulo small odd primes */ moduli = (unsigned short *) TMP_ALLOC (prime_limit * sizeof moduli[0]); for (i = 0; i < prime_limit; i++) moduli[i] = mpz_fdiv_ui (p, primes[i]); } for (difference = 0; ; difference += 2) { composite = 0; /* First check residues */ for (i = 0; i < prime_limit; i++) { int acc, pr; composite |= (moduli[i] == 0); acc = moduli[i] + 2; pr = primes[i]; moduli[i] = acc >= pr ? acc - pr : acc; } if (composite) continue; mpz_add_ui (p, p, difference); difference = 0; /* Miller-Rabin test */ if (mpz_millerrabin (p, 2)) break; } }
int mpz_probab_prime_p (mpz_srcptr n, int reps) { mp_limb_t r; mpz_t n2; /* Handle small and negative n. */ if (mpz_cmp_ui (n, 1000000L) <= 0) { if (mpz_cmpabs_ui (n, 1000000L) <= 0) { int is_prime; unsigned long n0; n0 = mpz_get_ui (n); is_prime = n0 & (n0 > 1) ? isprime (n0) : n0 == 2; return is_prime ? 2 : 0; } /* Negative number. Negate and fall out. */ PTR(n2) = PTR(n); SIZ(n2) = -SIZ(n); n = n2; } /* If n is now even, it is not a prime. */ if (mpz_even_p (n)) return 0; #if defined (PP) /* Check if n has small factors. */ #if defined (PP_INVERTED) r = MPN_MOD_OR_PREINV_MOD_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) PP, (mp_limb_t) PP_INVERTED); #else r = mpn_mod_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) PP); #endif if (r % 3 == 0 #if GMP_LIMB_BITS >= 4 || r % 5 == 0 #endif #if GMP_LIMB_BITS >= 8 || r % 7 == 0 #endif #if GMP_LIMB_BITS >= 16 || r % 11 == 0 || r % 13 == 0 #endif #if GMP_LIMB_BITS >= 32 || r % 17 == 0 || r % 19 == 0 || r % 23 == 0 || r % 29 == 0 #endif #if GMP_LIMB_BITS >= 64 || r % 31 == 0 || r % 37 == 0 || r % 41 == 0 || r % 43 == 0 || r % 47 == 0 || r % 53 == 0 #endif ) { return 0; } #endif /* PP */ /* Do more dividing. We collect small primes, using umul_ppmm, until we overflow a single limb. We divide our number by the small primes product, and look for factors in the remainder. */ { unsigned long int ln2; unsigned long int q; mp_limb_t p1, p0, p; unsigned int primes[15]; int nprimes; nprimes = 0; p = 1; ln2 = mpz_sizeinbase (n, 2); /* FIXME: tune this limit */ for (q = PP_FIRST_OMITTED; q < ln2; q += 2) { if (isprime (q)) { umul_ppmm (p1, p0, p, q); if (p1 != 0) { r = MPN_MOD_OR_MODEXACT_1_ODD (PTR(n), (mp_size_t) SIZ(n), p); while (--nprimes >= 0) if (r % primes[nprimes] == 0) { ASSERT_ALWAYS (mpn_mod_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) primes[nprimes]) == 0); return 0; } p = q; nprimes = 0; } else { p = p0; } primes[nprimes++] = q; } } } /* Perform a number of Miller-Rabin tests. */ return mpz_millerrabin (n, reps); }
int main() { constexpr size_t iterations = 1000; constexpr size_t width = 2048; constexpr size_t seed = 254148ul; std::cout << "This test shows speed comparison with GMP, it uses `miller_rabin` " "functions" << std::endl; std::cout << "Setup:" << std::endl; std::cout << "Iterations: " << iterations << std::endl; std::cout << "Number width: " << width << std::endl; std::cout << "Random seed: " << seed << std::endl; std::cout << std::endl; typedef std::chrono::nanoseconds duration_t; std::chrono::high_resolution_clock clock; std::chrono::time_point<std::chrono::high_resolution_clock> start, end; std::minstd_rand rnd(seed); { std::cout << "--- Testing pure `miller_rabin` tests (composite " "probability " "2^(-50))---" << std::endl; duration_t gmp_duration(0); duration_t primegen_duration(0); mpz_class j; for (size_t i = 0; i < iterations; ++i) { j = PrimeGen::Utils::independent_bits_generator< mpz_class, std::minstd_rand, 2048>(rnd); start = clock.now(); mpz_millerrabin(j.get_mpz_t(), 25); end = clock.now(); gmp_duration += std::chrono::duration_cast<duration_t>(end - start); start = clock.now(); PrimeGen::Tests::miller_rabin<mpz_class, 25>(j); end = clock.now(); primegen_duration += std::chrono::duration_cast<duration_t>(end - start); } std::cout << "Primegen test took: " << std::chrono::duration_cast<std::chrono::milliseconds>( primegen_duration).count() / 1000.0 << " seconds" << std::endl; std::cout << "GMP test took: " << std::chrono::duration_cast<std::chrono::milliseconds>( gmp_duration).count() / 1000.0 << " seconds" << std::endl; std::cout << std::endl << std::endl; } { std::cout << "--- Testing `miller_rabin` + trivial divisions (composite " "probability " "2^(-50))---" << std::endl; duration_t gmp_duration(0); duration_t primegen_duration(0); mpz_class j; for (size_t i = 0; i < iterations; ++i) { j = PrimeGen::Utils::independent_bits_generator< mpz_class, std::minstd_rand, 2048>(rnd); start = clock.now(); mpz_probab_prime_p(j.get_mpz_t(), 25); end = clock.now(); gmp_duration += std::chrono::duration_cast<duration_t>(end - start); start = clock.now(); PrimeGen::Tests::f1000_prime_factors(j) && PrimeGen::Tests::miller_rabin<mpz_class, 25>(j); end = clock.now(); primegen_duration += std::chrono::duration_cast<duration_t>(end - start); } std::cout << "Primegen test took: " << std::chrono::duration_cast<std::chrono::milliseconds>( primegen_duration).count() / 1000.0 << " seconds" << std::endl; std::cout << "GMP test took: " << std::chrono::duration_cast<std::chrono::milliseconds>( gmp_duration).count() / 1000.0 << " seconds" << std::endl; std::cout << std::endl << std::endl; } return 0; }
int mpz_probab_prime_p (mpz_srcptr n, int reps) { mp_limb_t r; /* Handle small and negative n. */ if (mpz_cmp_ui (n, 1000000L) <= 0) { int is_prime; if (mpz_sgn (n) < 0) { /* Negative number. Negate and call ourselves. */ mpz_t n2; mpz_init (n2); mpz_neg (n2, n); is_prime = mpz_probab_prime_p (n2, reps); mpz_clear (n2); return is_prime; } is_prime = isprime (mpz_get_ui (n)); return is_prime ? 2 : 0; } /* If n is now even, it is not a prime. */ if ((mpz_get_ui (n) & 1) == 0) return 0; #if defined (PP) /* Check if n has small factors. */ #if defined (PP_INVERTED) r = MPN_MOD_OR_PREINV_MOD_1 (PTR(n), SIZ(n), (mp_limb_t) PP, (mp_limb_t) PP_INVERTED); #else r = mpn_mod_1 (PTR(n), SIZ(n), (mp_limb_t) PP); #endif if (r % 3 == 0 #if BITS_PER_MP_LIMB >= 4 || r % 5 == 0 #endif #if BITS_PER_MP_LIMB >= 8 || r % 7 == 0 #endif #if BITS_PER_MP_LIMB >= 16 || r % 11 == 0 || r % 13 == 0 #endif #if BITS_PER_MP_LIMB >= 32 || r % 17 == 0 || r % 19 == 0 || r % 23 == 0 || r % 29 == 0 #endif #if BITS_PER_MP_LIMB >= 64 || r % 31 == 0 || r % 37 == 0 || r % 41 == 0 || r % 43 == 0 || r % 47 == 0 || r % 53 == 0 #endif ) { return 0; } #endif /* PP */ /* Do more dividing. We collect small primes, using umul_ppmm, until we overflow a single limb. We divide our number by the small primes product, and look for factors in the remainder. */ { unsigned long int ln2; unsigned long int q; mp_limb_t p1, p0, p; unsigned int primes[15]; int nprimes; nprimes = 0; p = 1; ln2 = mpz_sizeinbase (n, 2) / 30; ln2 = ln2 * ln2; for (q = PP_FIRST_OMITTED; q < ln2; q += 2) { if (isprime (q)) { umul_ppmm (p1, p0, p, q); if (p1 != 0) { r = mpn_mod_1 (PTR(n), SIZ(n), p); while (--nprimes >= 0) if (r % primes[nprimes] == 0) { ASSERT_ALWAYS (mpn_mod_1 (PTR(n), SIZ(n), (mp_limb_t) primes[nprimes]) == 0); return 0; } p = q; nprimes = 0; } else { p = p0; } primes[nprimes++] = q; } } } /* Perform a number of Miller-Rabin tests. */ return mpz_millerrabin (n, reps); }