diff --git a/doc/modular_arithmetic/extended_euclidean.qbk b/doc/modular_arithmetic/extended_euclidean.qbk index fb3dc57..097dba2 100644 --- a/doc/modular_arithmetic/extended_euclidean.qbk +++ b/doc/modular_arithmetic/extended_euclidean.qbk @@ -38,8 +38,6 @@ The extended Euclidean algorithm solves the integer relation /mx + ny/ = gcd(/m/ int y = res.y; // mx + ny = gcd(m,n) should now hold -Unlike most of the library, the extended Euclidean algorithm requires C++11 features. - [endsect] [section References] diff --git a/include/boost/integer/extended_euclidean.hpp b/include/boost/integer/extended_euclidean.hpp index 83d9a71..6326a1f 100644 --- a/include/boost/integer/extended_euclidean.hpp +++ b/include/boost/integer/extended_euclidean.hpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include namespace boost { namespace integer { @@ -16,27 +18,27 @@ namespace boost { namespace integer { // Solves mx + ny = gcd(m,n). Returns tuple with (gcd(m,n), x, y). template -struct euclidean_result_t { - Z gcd; - Z x; - Z y; +struct euclidean_result_t +{ + Z gcd; + Z x; + Z y; }; template -euclidean_result_t::is_signed, Z>::type> +typename boost::enable_if_c< std::numeric_limits< Z >::is_signed, euclidean_result_t< Z > >::type extended_euclidean(Z m, Z n) { if (m < 1 || n < 1) { - BOOST_THROW_EXCEPTION(std::domain_error("Arguments must be strictly positive.")); + BOOST_THROW_EXCEPTION(std::domain_error("extended_euclidean: arguments must be strictly positive")); } bool swapped = false; if (m < n) { - swapped = true; - using std::swap; - swap(m, n); + swapped = true; + boost::swap(m, n); } Z u0 = m; Z u1 = 1; @@ -49,23 +51,32 @@ extended_euclidean(Z m, Z n) Z w2; while(v0 > 0) { - Z q = u0/v0; - w0 = u0 - q*v0; - w1 = u1 - q*v1; - w2 = u2 - q*v2; - u0 = v0; - u1 = v1; - u2 = v2; - v0 = w0; - v1 = w1; - v2 = w2; + Z q = u0/v0; + w0 = u0 - q*v0; + w1 = u1 - q*v1; + w2 = u2 - q*v2; + u0 = v0; + u1 = v1; + u2 = v2; + v0 = w0; + v1 = w1; + v2 = w2; } - if (swapped) + euclidean_result_t< Z > result; + result.gcd = u0; + if (!swapped) { - return {u0, u2, u1}; + result.x = u1; + result.y = u2; } - return {u0, u1, u2}; + else + { + result.x = u2; + result.y = u1; + } + + return result; } }} diff --git a/include/boost/integer/mod_inverse.hpp b/include/boost/integer/mod_inverse.hpp index 2f07227..9f18ea8 100644 --- a/include/boost/integer/mod_inverse.hpp +++ b/include/boost/integer/mod_inverse.hpp @@ -8,7 +8,8 @@ #define BOOST_INTEGER_MOD_INVERSE_HPP #include #include -#include +#include +#include #include namespace boost { namespace integer { @@ -25,7 +26,7 @@ boost::optional mod_inverse(Z a, Z modulus) { if (modulus < 2) { - BOOST_THROW_EXCEPTION(std::domain_error("Modulus must be > 1.")); + BOOST_THROW_EXCEPTION(std::domain_error("mod_inverse: modulus must be > 1")); } // make sure a < modulus: a = a % modulus; @@ -34,7 +35,7 @@ boost::optional mod_inverse(Z a, Z modulus) // a doesn't have a modular multiplicative inverse: return boost::none; } - euclidean_result_t u = extended_euclidean(a, modulus); + boost::integer::euclidean_result_t u = boost::integer::extended_euclidean(a, modulus); if (u.gcd > 1) { return boost::none; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a0a8dd7..b1057d6 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -17,8 +17,8 @@ test-suite integer [ run integer_mask_test.cpp ] [ run static_log2_test.cpp ] [ run static_min_max_test.cpp ] - [ run extended_euclidean_test.cpp : : : [ requires cxx11_unified_initialization_syntax sfinae_expr ] ] - [ run mod_inverse_test.cpp : : : [ requires cxx11_unified_initialization_syntax sfinae_expr ] ] + [ run extended_euclidean_test.cpp ] + [ run mod_inverse_test.cpp ] [ compile integer_traits_include_test.cpp ] [ compile integer_include_test.cpp ] [ compile integer_mask_include_test.cpp ]