《编程之美》学而思 - 最大公约数问题
flyfish
greatest common divisor 最大公约数
Euclidean algorithm, or Euclid’s algorithm 欧几里德算法
common divisor 公约数
divisor 除数; 因子;
主要方法
列举法:各自列出约数,再找出最大的公约数。
质因数分解法:两数各作素因数分解,然后取出共有的项乘起来。
短除法
辗转相除法(欧几里德算法)
辗转相除法首次出现于欧几里得的《几何原本》
质因数(素因数或质因子)在数论里是指能整除给定正整数的质数。除了1以外,两个没有其他共同质因子的正整数称为互质。因为1没有质因子,1与任何正整数(包括1本身)都是互质。正整数的因数分解可将正整数表示为一连串的质因子相乘
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a%b);
}
/* Standard C Function: Greatest Common Divisor */
int gcd ( int a, int b )
{
int c;
while ( a != 0 ) {
c = a; a = b%a; b = c;
}
return b;
}
/* Recursive Standard C Function: Greatest Common Divisor */
int
gcdr ( int a, int b )
{
if ( a==0 ) return b;
return gcdr ( b%a, a );
}
标准库 std::gcd(C++17)
VS 2017.3 [P2] C++17 P0295R0 gcd(), lcm()
Libstdc++ 中的算法
欧几里得整环(Euclidean domain)是一种能作辗转相除法的整环
Euclidean domain 和 Euclidean ring是一个意思
template<typename _EuclideanRingElement>
_EuclideanRingElement
__gcd(_EuclideanRingElement __m, _EuclideanRingElement __n)
{
while (__n != 0)
{
_EuclideanRingElement __t = __m % __n;
__m = __n;
__n = __t;
}
return __m;
}
Boost库中的算法
#include
common_factor_rt.hpp
boost::math::gcd
gcd_euclidean
(
RingType a,
RingType b
)
{
// Avoid repeated construction
#ifndef __BORLANDC__
RingType const zero = static_cast( 0 );
#else
RingType zero = static_cast( 0 );
#endif
// Reduce by GCD-remainder property [GCD(a,b) == GCD(b,a MOD b)]
while ( true )
{
if ( a == zero )
return b;
b %= a;
if ( b == zero )
return a;
a %= b;
}
}
二进制最大公约数算法将除法操作替换成了二进制的移位
// Greatest common divisor for unsigned binary integers
template < typename BuiltInUnsigned >
BuiltInUnsigned
gcd_binary
(
BuiltInUnsigned u,
BuiltInUnsigned v
)
{
if ( u && v )
{
// Shift out common factors of 2
unsigned shifts = 0;
while ( !(u & 1u) && !(v & 1u) )
{
++shifts;
u >>= 1;
v >>= 1;
}
// Start with the still-even one, if any
BuiltInUnsigned r[] = { u, v };
unsigned which = static_cast<bool>( u & 1u );
// Whittle down the values via their differences
do
{
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
while ( !(r[ which ] & 1u) )
{
r[ which ] = (r[which] >> 1);
}
#else
// Remove factors of two from the even one
while ( !(r[ which ] & 1u) )
{
r[ which ] >>= 1;
}
#endif
// Replace the larger of the two with their difference
if ( r[!which] > r[which] )
{
which ^= 1u;
}
r[ which ] -= r[ !which ];
}
while ( r[which] );
// Shift-in the common factor of 2 to the residues' GCD
return r[ !which ] << shifts;
}
else
{
// At least one input is zero, return the other
// (adding since zero is the additive identity)
// or zero if both are zero.
return u + v;
}
}