木匣子

Web/Game/Programming/Life etc.

异或与加法

异或(xor),是计算机中一个很普遍的运算。虽然没有他的兄弟与、或、非那样在生活中被人们熟知,也很少有人在谈论事情的时候直接使用它,但你可能偶尔听到这样的对话(通常都不是那么友好):

这件事情,要么你来做,要么我来做,不然就这么搁着。

是的,这就是异或。但我们不会说这件事情我*异或*你来做,除非对方是一个GEEK。不过它们的意思确实是一样的。

在异或的法则下,只有两个输入不相同的情况才为真。它的真值表如下:

A B XOR  
0 0 0  
0 1 1  
1 0 1  
1 1 0

运用

多控开关

这么奇怪的东西在生活中有什么运用呢?可曾记得小时候在冬天的夜晚,准备上床睡觉的时候,猛地跑去门边关了灯,然后又迅速的冲回被窝的情形吗。可曾记得邻居家小朋友家里的灯可以在门边打开,然后在床边的另一个开关关掉么?

没错,这就是异或啊!当两个开关状态一致的时候,灯是关着的,这时候只要改变其中一个开关,灯就亮了,这时候再改变其中一个开关的状态,它们的状态又回到一致,灯就关了。

如果有兴趣知道这样的开关电路是怎么连接的,可以参看维基百科

硬件加法

如果你仔细看看异或的真值表,你会发现它和二进制加法的是不是很像:

0+0=0  
0+1=1  
1+0=1  
1+1=0 (进位)

事实上,在计算机硬件中,加法就是通过异或来实现的。而进位问题只要再加一个与门,构成半加器就解决了。加法器由多个半加器组成。

如果你些内容很感兴趣,推荐你读一读 编码的奥秘 这本书。

交换两个变量的值

在一些场合上,你可能会看到有人用异或写出了能够交换两个变量的值的算法,而且不需要用到第三个临时变量。

A=A^B;
B=A^B;
A=A^B;

这里我就不去分析这绕口令式的算法了,它除了把你搞晕以外还能让古老的计算机跑得稍快一点。实际上现代编译器已经能自动识别你的意图,帮你优化此类交换变量的值的语句,你大可写得直白一些。

不过这里有趣的一点是,如果你把A跟同一个东西异或偶数次,它就跟没发生过一样,A还是A。现在你能看明白上面那个算法发生了什么吗?知道的人很兴奋地写出了另一个绕口令:

A=A+B;
B=A-B;
A=A-B;

其中的道理是一样的,还记得刚才说过异或和加法之间的暧昧关系么。不过这个方法要注意防止溢出,所以比较不给力。

其它

此外,异或还可以用来解决一些根本不存在的问题:

Google面试题
一个数组存放若干整数,一个数出现奇数次,其余数均出现偶数次,找出这个出现奇数次的数?

有兴趣的话,可以看看更加复杂的变形及解法:一道算法题引出的异或运算