最大公约数gcd实现

原文地址:https://hbfs.wordpress.com/2013/12/10/the-speed-of-gcd/

最大公约数求法

  • 最朴素的方法:如果一个是0,返回另一个;否则,分别找到a,b所有的约数,找公共最大的约数
  • 欧几里得辗转法:最原始提出的方法应该是辗转相减,然后改进为辗转相除(取模)
  • 二进制gcd:这主要是因为gcd有以下3个特点:
    • 如果a,b都是偶数,那么gcd(a,b) = gcd(a/2,b/2)*2
    • 如果a是奇数,b是偶数,那么gcd(a,b) = gcd(a,b/2)
    • 如果a,b都是奇数,那么gcd(a,b) = gcd((a-b)/2,b)

代码实现

代码实现了辗转相除的递归、迭代版本,还有二进制gcd的基本版、迭代复合版、使用内建函数版。

template <typename T>
T gcd_recursive( T a, T b ) {
    return b == 0 ? a : gcd_recursive( b, a % b );
}

template <typename T>
T gcd_iterative2( T a, T b ) {
    T t;
    while( b != 0 ) {
        t = a % b;
        a = b;  
        b = t;  
    }  
    return a;
}

template <typename T>
T gcd_iterative( T a, T b ) {
    while( a != 0 ) {
        b %= a;
        if( b == 0 ) return a;
        a %= b;
    }  
    return b;
}
template <typename T>
T gcd_binary( T a, T b ) {
    if( a == 0 ) return b;
    if( b == 0 ) return a;

    int k = 0;
    while( ((a | b) & 1) == 0 ) {
        a >>= 1;
        b >>= 1;
        ++k;
    }

    while( (a & 1) == 0 ) a >>= 1;
    do {
        while( (b & 1) == 0 ) b >>= 1;
        if( a > b ) {
            T t = a;
            a = b;
            b = t;
        }
        b -= a;
    } while( b != 0 );
    return a << k;
}

// __builtin_ctz返回一个整数末尾0的个数,count trailing zero
template <typename T>
T gcd_binary_builtin( T a, T b ) {
    if( a == 0 ) return b;
    if( b == 0 ) return a;

    int k = __builtin_ctz( a | b );
    a >>=  __builtin_ctz( a );

    do {
        b >>=  __builtin_ctz( b );
        if( a > b ) {
            T t = a;
            a = b;
            b = t;
        }
        b -= a;
    } while( b != 0 );
    return a << k;
}

template <typename T>
T gcd_binary_recur( T a, T b ) {
    if( a == 0 ) return b;
    if( b == 0 ) return a;

    int k = 0;
    while( ((a | b) & 1) == 0 ) {
        a >>= 1;
        b >>= 1;
        ++k;
    }
    return gcd_recursive( a, b ) << k;
}

运行结果

随机生成5000000对整数,然后调用gcd的不同版本,生成过程大概是0.08s,所以对整体时间影响可以忽略。

函数时间备注
gcd_recursive0m1.078s意外的是,它比迭代版本快一点
gcd_iterative/gcd_iterative20m1.098sgcd_iterative比gcd_iterative2稍快,可能跟展开有关
gcd_binary0m1.523s因为每次只能移一位,所以速度慢
gcd_binary_recur0m1.092s还不如单纯递归版本
gcd_binary_builtin0m0.821s这个是最快的

其实二进制gcd计算次数会更多一点,但是它执行的都是适合计算机的二进制位操作,而不是耗时的除法操作,但是基本版本移位操作太多,所以表现很差,内建函数版本充分利用了cpu指令,所以是速度最快的。

参考
[1] https://hbfs.wordpress.com/2013/12/10/the-speed-of-gcd/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值