00001 00002 /* 00003 The Extended Integer (XInt) Library 00004 A fast, portable C++ library for multi-precision integer math 00005 Copyright 2010 by Chad Nelson 00006 00007 Distributed under the Boost Software License, Version 1.0. 00008 See accompanying file LICENSE_1_0.txt or copy at 00009 http://www.boost.org/LICENSE_1_0.txt 00010 00011 See http://www.boost.org/libs/xint for library home page. 00012 */ 00013 00020 #ifndef BOOST_INCLUDED_XINT_PRIME_HPP 00021 #define BOOST_INCLUDED_XINT_PRIME_HPP 00022 00024 namespace boost { 00025 namespace xint { 00026 namespace detail { 00027 00028 inline std::vector<int> sieveOfEratosthenes(int upTo) { 00029 std::vector<int> sieve; 00030 sieve.reserve(upTo); 00031 00032 // Zero and one aren't prime, by definition. 00033 sieve.push_back(0); 00034 sieve.push_back(0); 00035 00036 for (int p = 2; p < upTo; ++p) sieve.push_back(p); 00037 00038 std::vector<int> ret; 00039 00040 int *p = &sieve[0], *e = p + upTo; 00041 while (p < e) { 00042 if (*p == 0) { ++p; continue; } 00043 ret.push_back(*p); 00044 00045 int *p2 = p + (*p); 00046 while (p2 < e) { *p2 = 0; p2 += *p; } 00047 00048 ++p; 00049 } 00050 00051 return ret; 00052 } 00053 00054 // The Miller-Rabin Probabilistic Test of Primality 00055 BOOST_XINT_RAWINT_TPL 00056 int isProbablePrimeBaseB(const BOOST_XINT_RAWINT n, const BOOST_XINT_RAWINT b, 00057 callback_t callback) 00058 { 00059 const BOOST_XINT_RAWINT one(1), nMinus1(n - one); 00060 00061 // Find r and a satisfying: n - 1 = 2^a * r, r odd 00062 BOOST_XINT_RAWINT r(nMinus1); 00063 unsigned long a = 0; 00064 while (r.is_even()) { r >>= 1; ++a; } 00065 00066 // We check the congruence class of b^((2^i)r) % n for each i 00067 // from 0 to a - 1. If any one is correct, then n passes. 00068 // Otherwise, n fails. 00069 BOOST_XINT_RAWINT test = powmod(b, r, n); 00070 if (test == one || test == nMinus1) 00071 return 1; // Better than 3/4 chance it's prime 00072 00073 while (a-- > 0) { 00074 test = sqrmod(test, n); 00075 if (test == nMinus1) return 1; 00076 } 00077 00078 if (callback && !callback()) return -1; 00079 return 0; 00080 } 00081 00082 BOOST_XINT_RAWINT_TPL 00083 int is_prime(const BOOST_XINT_RAWINT n, callback_t callback) { 00084 BOOST_XINT_RAWINT tmp(2); 00085 if (n < tmp) exception_handler<>::call(__FILE__, __LINE__, 00086 exceptions::invalid_argument("xint::is_prime cannot test numbers below " 00087 "2")); 00088 00089 // First we trial-divide it by the primes below 2000 00090 static const std::vector<int> low_primes(sieveOfEratosthenes(2000)); 00091 const BOOST_XINT_RAWINT zero; 00092 std::vector<int>::const_iterator i = low_primes.begin(), ie = 00093 low_primes.end(); 00094 for (; i != ie; ++i) { 00095 tmp.set_unsigned(*i); 00096 if ((n % tmp) == zero) 00097 return (n == tmp); 00098 } 00099 00100 // Ensure that we've got a random generator. 00101 static std::auto_ptr<default_random_generator> gen(new 00102 default_random_generator); 00103 detail::random_generator<default_random_generator> random(*gen.get()); 00104 00105 // Run the number through the Miller-Rabin Probabilistic Test of Primality 00106 // a few times to see if it's actually (probably) prime. 00107 for (int count = 0; count < 5; ++count) { 00108 unsigned int k = random(); 00109 tmp.set_unsigned(k); 00110 int isP = isProbablePrimeBaseB(n, tmp, callback); 00111 if (isP <= 0) return isP; 00112 } 00113 return 1; // Appears to be prime! 00114 } 00115 00116 BOOST_XINT_RAWINT_TPL 00117 template <typename GenType> 00118 BOOST_XINT_RAWINT BOOST_XINT_RAWINT::random_prime(GenType& gen, std::size_t 00119 size_in_bits, callback_t callback) 00120 { 00121 if (size_in_bits < 2) exception_handler<>::call(__FILE__, __LINE__, 00122 exceptions::invalid_argument("cannot create prime numbers smaller than " 00123 "two bits")); 00124 00125 // Call the callback for the first time 00126 if (callback && !callback()) return 0; 00127 00128 // If, by rare chance, the number we're testing gets larger than the number 00129 // of bits requested, we have to start over with a new random number of the 00130 // proper size. 00131 BOOST_XINT_RAWINT pe; 00132 pow2(pe, size_in_bits + 1); 00133 00134 const BOOST_XINT_RAWINT two(2); 00135 while (1) { 00136 BOOST_XINT_RAWINT target = random_by_size(gen, size_in_bits, true, true, 00137 false); 00138 while (target < pe) { 00139 int r = is_prime(target, callback); 00140 if (r < 0) return 0; 00141 if (r == 1) return target; 00142 target += two; 00143 } 00144 } 00145 } 00146 00147 } // namespace detail 00148 } // namespace xint 00149 } // namespace boost 00151 00152 #endif // BOOST_INCLUDED_XINT_PRIME_HPP
© Copyright Chad Nelson, 2010-2011. 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)