1 ///////////////////////////////////////////////////////////////
2 // Copyright 2012 John Maddock. Distributed under the Boost
3 // Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
6 #ifndef BOOST_MP_MR_HPP
7 #define BOOST_MP_MR_HPP
11 #include <type_traits>
12 #include <boost/multiprecision/detail/standalone_config.hpp>
13 #include <boost/multiprecision/integer.hpp>
14 #include <boost/multiprecision/detail/uniform_int_distribution.hpp>
15 #include <boost/multiprecision/detail/assert.hpp>
18 namespace multiprecision {
22 bool check_small_factors(const I& n)
24 constexpr const std::uint32_t small_factors1[] = {
25 3u, 5u, 7u, 11u, 13u, 17u, 19u, 23u};
26 constexpr const std::uint32_t pp1 = 223092870u;
28 std::uint32_t m1 = integer_modulus(n, pp1);
30 for (std::size_t i = 0; i < sizeof(small_factors1) / sizeof(small_factors1[0]); ++i)
32 BOOST_MP_ASSERT(pp1 % small_factors1[i] == 0);
33 if (m1 % small_factors1[i] == 0)
37 constexpr const std::uint32_t small_factors2[] = {
38 29u, 31u, 37u, 41u, 43u, 47u};
39 constexpr const std::uint32_t pp2 = 2756205443u;
41 m1 = integer_modulus(n, pp2);
43 for (std::size_t i = 0; i < sizeof(small_factors2) / sizeof(small_factors2[0]); ++i)
45 BOOST_MP_ASSERT(pp2 % small_factors2[i] == 0);
46 if (m1 % small_factors2[i] == 0)
50 constexpr const std::uint32_t small_factors3[] = {
51 53u, 59u, 61u, 67u, 71u};
52 constexpr const std::uint32_t pp3 = 907383479u;
54 m1 = integer_modulus(n, pp3);
56 for (std::size_t i = 0; i < sizeof(small_factors3) / sizeof(small_factors3[0]); ++i)
58 BOOST_MP_ASSERT(pp3 % small_factors3[i] == 0);
59 if (m1 % small_factors3[i] == 0)
63 constexpr const std::uint32_t small_factors4[] = {
64 73u, 79u, 83u, 89u, 97u};
65 constexpr const std::uint32_t pp4 = 4132280413u;
67 m1 = integer_modulus(n, pp4);
69 for (std::size_t i = 0; i < sizeof(small_factors4) / sizeof(small_factors4[0]); ++i)
71 BOOST_MP_ASSERT(pp4 % small_factors4[i] == 0);
72 if (m1 % small_factors4[i] == 0)
76 constexpr const std::uint32_t small_factors5[6][4] = {
77 {101u, 103u, 107u, 109u},
78 {113u, 127u, 131u, 137u},
79 {139u, 149u, 151u, 157u},
80 {163u, 167u, 173u, 179u},
81 {181u, 191u, 193u, 197u},
82 {199u, 211u, 223u, 227u}};
83 constexpr const std::uint32_t pp5[6] =
86 113u * 127u * 131u * 137u,
87 139u * 149u * 151u * 157u,
88 163u * 167u * 173u * 179u,
89 181u * 191u * 193u * 197u,
90 199u * 211u * 223u * 227u};
92 for (std::size_t k = 0; k < sizeof(pp5) / sizeof(*pp5); ++k)
94 m1 = integer_modulus(n, pp5[k]);
96 for (std::size_t i = 0; i < 4; ++i)
98 BOOST_MP_ASSERT(pp5[k] % small_factors5[k][i] == 0);
99 if (m1 % small_factors5[k][i] == 0)
106 inline bool is_small_prime(std::size_t n)
108 constexpr const unsigned char p[] =
110 3u, 5u, 7u, 11u, 13u, 17u, 19u, 23u, 29u, 31u,
111 37u, 41u, 43u, 47u, 53u, 59u, 61u, 67u, 71u, 73u,
112 79u, 83u, 89u, 97u, 101u, 103u, 107u, 109u, 113u,
113 127u, 131u, 137u, 139u, 149u, 151u, 157u, 163u,
114 167u, 173u, 179u, 181u, 191u, 193u, 197u, 199u,
116 for (std::size_t i = 0; i < sizeof(p) / sizeof(*p); ++i)
125 typename std::enable_if<std::is_convertible<I, unsigned>::value, unsigned>::type
126 cast_to_unsigned(const I& val)
128 return static_cast<unsigned>(val);
131 typename std::enable_if<!std::is_convertible<I, unsigned>::value, unsigned>::type
132 cast_to_unsigned(const I& val)
134 return val.template convert_to<unsigned>();
137 } // namespace detail
139 template <class I, class Engine>
140 typename std::enable_if<number_category<I>::value == number_kind_integer, bool>::type
141 miller_rabin_test(const I& n, std::size_t trials, Engine& gen)
143 using number_type = I;
146 return true; // Trivial special case.
147 if (bit_test(n, 0) == 0)
148 return false; // n is even
150 return detail::is_small_prime(detail::cast_to_unsigned(n));
152 if (!detail::check_small_factors(n))
155 number_type nm1 = n - 1;
157 // Begin with a single Fermat test - it excludes a lot of candidates:
159 number_type q(228), x, y; // We know n is greater than this, as we've excluded small factors
165 std::size_t k = lsb(q);
168 // Declare our random number generator:
169 boost::multiprecision::uniform_int_distribution<number_type> dist(2, n - 2);
172 // Execute the trials:
174 for (std::size_t i = 0; i < trials; ++i)
187 return false; // test failed
190 return false; // failed
194 return true; // Yeheh! probably prime.
198 typename std::enable_if<number_category<I>::value == number_kind_integer, bool>::type
199 miller_rabin_test(const I& x, std::size_t trials)
201 static std::mt19937 gen;
202 return miller_rabin_test(x, trials, gen);
205 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class Engine>
206 bool miller_rabin_test(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& n, std::size_t trials, Engine& gen)
208 using number_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
209 return miller_rabin_test(number_type(n), trials, gen);
212 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
213 bool miller_rabin_test(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& n, std::size_t trials)
215 using number_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
216 return miller_rabin_test(number_type(n), trials);
219 }} // namespace boost::multiprecision