这个最大公约数算法如何工作?

时间:2018-02-05 18:23:17

标签: c algorithm greatest-common-divisor

我刚刚在网上找到了这段代码,用于计算2个数字的最大公约数。它是如何工作的?

int gcd(int a, int b){
    while(b) b ^= a ^= b ^= a %= b;
    return a;
}

2 个答案:

答案 0 :(得分:5)

首先,我不相信这实际上是正确的C,因为相同的变量在单个语句中被多次更新而没有插入序列点。一个更简单的例子是:

a += ++a;

外部作业左侧的a是否选取原作a是未定义的(语句中没有序列点)。

话说回来,循环体的意图似乎是:

a %= b;
b ^= a;
a ^= b;
b ^= a;

这相当于:

a %= b;
t = b;
b = a;
a = t;

换句话说,它将a设置为a % b,然后交换ab

使用^运算符进行交换首先将b设置为a ^ b,然后使用该值对a进行xoring以获取原始b ,然后将新ba ^ b)与原始b进行xor,以获得原始a。在不使用临时变量的情况下交换ab只是一种令人费解的方式。

算法本身只是从一个减去另一个的倍数,然后切换两个数字,一直持续到其中一个为零,此时另一个将包含GCD(这是基于欧几里得算法)。

您可以通过展开循环来完全避免交换:

for (;;) {
    if (b == 0) return a;
    a %= b;
    if (a == 0) return b;
    b %= a;
}

答案 1 :(得分:1)

这是使用Euclid算法找到最大公约数,以及使用xor技巧交换两个变量。

Euclid的算法首先采用a mod b然后交换ab,重复直到其中一个为0.然后另一个是结果。您可以在Wikipedia article上了解更多相关信息。

交换这两个变量的xor技巧仅用于避免使用临时变量。您可以在Wikipedia article上详细了解其原因。让我举一个例子给你,这样你就可以看到它是如何工作的。

int a = 0b1100;
int b = 0b1010;

a = a ^ b;  // 1100 ^ 1010 = 0110
b = a ^ b;  // 0110 ^ 1010 = 1100
a = a ^ b;  // 0110 ^ 1100 = 1010
// Now a and b are swapped.