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_GCD_HPP 00021 #define BOOST_INCLUDED_XINT_GCD_HPP 00022 00024 namespace boost { 00025 namespace xint { 00026 namespace detail { 00027 00028 BOOST_XINT_RAWINT_TPL 00029 struct gcd_core { 00030 gcd_core(const BOOST_XINT_RAWINT n, const BOOST_XINT_RAWINT m): u1(1), u2(), 00031 u3(n) 00032 { 00033 const BOOST_XINT_RAWINT zero; 00034 BOOST_XINT_RAWINT t1(m), t2(n), t3(m); 00035 --t2; 00036 do { 00037 do { 00038 if (u3.is_even()) { 00039 if (u1.is_odd() || u2.is_odd()) { u1 += m; u2 += n; } 00040 u1 >>= 1; 00041 u2 >>= 1; 00042 u3 >>= 1; 00043 } 00044 00045 if (t3.is_even() || u3 < t3) { 00046 // Swap the u's with the t's 00047 using std::swap; 00048 swap(u1, t1); 00049 swap(u2, t2); 00050 swap(u3, t3); 00051 } 00052 } while (u3.is_even()); 00053 00054 while (u1 < t1 || u2 < t2) { u1 += m; u2 += n; } 00055 u1 -= t1; u2 -= t2; u3 -= t3; 00056 } while (t3 > zero); 00057 00058 while (u1 >= m && u2 >= n) { u1 -= m; u2 -= n; } 00059 } 00060 00061 BOOST_XINT_RAWINT u1, u2, u3; 00062 }; 00063 00064 BOOST_XINT_RAWINT_TPL 00065 void gcd(BOOST_XINT_RAWINT& target, const BOOST_XINT_RAWINT num1, const 00066 BOOST_XINT_RAWINT num2) 00067 { 00068 if (num1.is_zero() && num2.is_zero()) { 00069 target.set(0); 00070 } else if (num1.is_zero()) { 00071 target = num2; 00072 } else if (num2.is_zero()) { 00073 target = num1; 00074 } else { 00075 BOOST_XINT_RAWINT n(num1, false), m(num2, false); 00076 00077 std::size_t k = 0; 00078 if (!getbit(n, k) && !getbit(m, k)) ++k; 00079 if (k != 0) { n >>= k; m >>= k; } 00080 00081 gcd_core<Bits, Secure, Alloc> core(n, m); 00082 if (core.u3.is_zero()) { 00083 target.set(1); 00084 target <<= k; 00085 } else { 00086 target = core.u3; 00087 target <<= k; 00088 } 00089 } 00090 } 00091 00092 BOOST_XINT_RAWINT_TPL 00093 void lcm(BOOST_XINT_RAWINT& target, const BOOST_XINT_RAWINT num1, const 00094 BOOST_XINT_RAWINT num2) 00095 { 00096 if (num1.is_zero() || num2.is_zero()) { 00097 target.set(0); 00098 } else { 00099 BOOST_XINT_RAWINT common; 00100 gcd(common, num1, num2); 00101 00102 target = num1 * num2 / common; 00103 target.negative = false; 00104 target.trim(); 00105 } 00106 } 00107 00110 BOOST_XINT_RAWINT_TPL 00111 BOOST_XINT_RAWINT invmod(const BOOST_XINT_RAWINT n, const BOOST_XINT_RAWINT m) { 00112 if (m.is_zero() || m.negative) exception_handler<>::call(__FILE__, __LINE__, 00113 exceptions::invalid_modulus()); 00114 00115 if (n.is_zero()) { 00116 return 0; 00117 } else if (n.negative) { 00118 BOOST_XINT_RAWINT target = invmod(n.abs(), m); 00119 if (!target.is_zero()) { 00120 target.negative = true; 00121 target += m; 00122 } 00123 target.trim(); 00124 return target; 00125 } else { 00126 if (n.is_even() && m.is_even()) { 00127 // GCD != 1, no inverse possible. 00128 return 0; 00129 } else { 00130 gcd_core<Bits, Secure, Alloc> core(n, m); 00131 if (core.u3 != BOOST_XINT_RAWINT(1)) { 00132 // GCD != 1, no inverse possible. 00133 return 0; 00134 } else return core.u1; 00135 } 00136 } 00137 } 00138 00139 } // namespace detail 00140 } // namespace xint 00141 } // namespace boost 00143 00144 #endif // BOOST_INCLUDED_XINT_GCD_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)