最大公约数问题是经典的数学问题,本文分析下最大公约数问题的计算优化思路。

分析:

1、求x,y的最大公约数,用辗转相除法

设k = x / y,b = x % y,则x = ky + b,
因此( x, y ) = ( ky +b, y ) = (y, b),
因此( x, y ) = ( y, x % y ),并且( 0, x) = x。

关键就是将两个较大的数的公约数转化为两个较小数的公约数。

int gcd( int x, int y )
{
    return (y==0) ? x : gcd( y, x%y );
}

2、进一步,由于取模运算是比较慢的,考虑到(x, y) = ( x - y, y ) 假设x > y,因此可以加速。

int gcd( int x, int y )
{// x >= y
    if ( x < y )
       return gcd(y, x);
 
    return (y==0) ? x : gcd(x-y, y);
}

3、更进一步,虽然减法加速了,但是递进的速度不够快,考虑极端的情况( 1000000000, 1 ),这样用方法2将非常郁闷。还是需要想办法,尽量结合上面两种优势:向目标递进速度与每次运算效率。

注意到:

若x = k * x1, y = k * y1,则(x, y) = (x1, y1),
另外,对于素数p,若x = p * x1,且y % p != 0,那么(x, y) = (p*x1, y) = (x1, y)

这个素数p的最优选择就是2,因为除以2可以用移位操作简单的代替:

若x, y均为偶数: ( x, y ) = 2*( x>>1, y>>1 )
若x奇,y偶:     ( x, y ) = (x, y>>1)
若x偶,y奇:     ( x, y ) = (x>>1, y)
若x,y均为奇数:  ( x, y ) = (x, x-y),由于x-y为偶,下一步会除以2
bool IsEven( int n )
{
    return !(n & 0x01);
}
 
int gcd( int x, int y )
{// x >= y
    if ( x < y )
       return gcd(y, x);
 
    if ( y == 0 )
    {
       return x;
    }
    else
    {
       if ( IsEven(x) )
       {
           if ( IsEven(y) )
              return (gcd(x>>1, y>>1) << 1);
           else
              return gcd(x>>1, y);
       }
       else
       {
           if ( IsEven(y) )
              return gcd(x, y>>1);
           else
              return gcd(x-y, y);
       }
    }
}