我刚刚在网上找到了这段代码,用于计算2个数字的最大公约数。它是如何工作的?
int gcd(int a, int b){
while(b) b ^= a ^= b ^= a %= b;
return a;
}
答案 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
,然后交换a
和b
。
使用^
运算符进行交换首先将b
设置为a ^ b
,然后使用该值对a
进行xoring以获取原始b
,然后将新b
(a ^ b
)与原始b
进行xor,以获得原始a
。在不使用临时变量的情况下交换a
和b
只是一种令人费解的方式。
算法本身只是从一个减去另一个的倍数,然后切换两个数字,一直持续到其中一个为零,此时另一个将包含GCD(这是基于欧几里得算法)。
您可以通过展开循环来完全避免交换:
for (;;) {
if (b == 0) return a;
a %= b;
if (a == 0) return b;
b %= a;
}
答案 1 :(得分:1)
这是使用Euclid算法找到最大公约数,以及使用xor技巧交换两个变量。
Euclid的算法首先采用a mod b
然后交换a
和b
,重复直到其中一个为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.