/////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2024. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// // This Miller-Rabin primality test is loosely based on // an adaptation of some code from Boost.Multiprecision. // The Boost.Multiprecision code can be found here: // https://www.boost.org/doc/libs/1_78_0/libs/multiprecision/doc/html/boost_multiprecision/tut/primetest.html #include #include #include #include #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warray-bounds" #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-copy" #endif #endif #include #include #include namespace local_miller_rabin { template auto lexical_cast(const UnsignedIntegralType& u) -> std::string { std::stringstream ss; ss << u; return ss.str(); } } // namespace local_miller_rabin #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example008a_miller_rabin_prime() -> bool #else auto ::math::wide_integer::example008a_miller_rabin_prime() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using boost_wide_integer_type = boost::multiprecision::number(UINT32_C(512))>, boost::multiprecision::et_off>; #else using boost_wide_integer_type = boost::multiprecision::number(UINT32_C(512))>, boost::multiprecision::et_off>; #endif // This example uses wide_integer's uniform_int_distribution to select // prime candidates. These prime candidates are subsequently converted // (via string-streaming) to Boost.Multiprecision integers. #if defined(WIDE_INTEGER_NAMESPACE) using local_wide_integer_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t (std::numeric_limits::digits)>; using local_distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution(std::numeric_limits::digits)>; #else using local_wide_integer_type = ::math::wide_integer::uintwide_t (std::numeric_limits::digits)>; using local_distribution_type = ::math::wide_integer::uniform_int_distribution(std::numeric_limits::digits)>; #endif using random_engine1_type = std::mt19937; using random_engine2_type = std::linear_congruential_engine; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto seed_start = ::util::util_pseudorandom_time_point_seed::value(); random_engine1_type gen1(static_cast(seed_start)); random_engine2_type gen2(static_cast(seed_start)); // Select prime candidates from a range of 10^150 ... max(uint512_t)-1. constexpr local_wide_integer_type dist_min ( "1" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" ); constexpr auto dist_max = local_wide_integer_type { (std::numeric_limits::max)() - static_cast(INT8_C(1)) }; local_distribution_type dist { dist_min, dist_max }; boost_wide_integer_type p0; boost_wide_integer_type p1; auto dist_func = [&dist, &gen1]() // NOLINT(modernize-use-trailing-return-type) { const auto n = dist(gen1); return boost_wide_integer_type(local_miller_rabin::lexical_cast(n)); }; for(;;) { p0 = dist_func(); const auto p0_is_probably_prime = boost::multiprecision::miller_rabin_test(p0, 25U, gen2); if(p0_is_probably_prime) { break; } } const auto seed_next = ::util::util_pseudorandom_time_point_seed::value(); gen1.seed(static_cast(seed_next)); for(;;) { p1 = dist_func(); const auto p1_is_probably_prime = boost::multiprecision::miller_rabin_test(p1, 25U, gen2); if(p1_is_probably_prime) { break; } } const boost_wide_integer_type gd = gcd(p0, p1); const auto result_is_ok = ( (p0 > boost_wide_integer_type(local_miller_rabin::lexical_cast(dist_min))) && (p1 > boost_wide_integer_type(local_miller_rabin::lexical_cast(dist_min))) && (p0 != 0U) && (p1 != 0U) && (p0 != p1) && (gd == 1U)); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE008A_MILLER_RABIN_PRIME) #include #include auto main() -> int // NOLINT(bugprone-exception-escape) { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example008a_miller_rabin_prime(); #else const auto result_is_ok = ::math::wide_integer::example008a_miller_rabin_prime(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic pop #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif