逻辑运算和位运算——异或
##逻辑运算和位运算——异或
如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
更通俗的讲就是:两个值不同为真,两个值相同为假。
| 1 | 0 | |
|---|---|---|
| 1 | 0(假) | 1(真) |
| 0 | 1(真) | 0(假) |
异或运算真值表
上面是异或在逻辑运算中的使用。但如果异或放在位运算中,就有很多的应用场景。
我们把上面的表抽取出来,看成位运算的话可以得到下面两个表,并得出两个简单结论:
| 1 | 0 | |
|---|---|---|
| 0 | 1 | 0 |
用0进行按位异或运算
结论一:如果一个数用0进行按位异或的话,会得到这个数本身。
| 1 | 0 | |
|---|---|---|
| 1 | 0 | 1 |
用1进行按位异或运算
结论二:如果一个数用1进行按位异或的话,会得到相反的数。也就是取反。
用上面的两个结论,我们有四种基本的异或使用环境:
使用环境一:使某些特定的位取反。
1 | a = 10100001; |
使用环境二:实现两个值的交换,而不必使用临时变量。
1 | a = a ^ b; // a=0b10100111 |
使用环境三:将变量自身置零。
1 | a = 10100001; |
使用环境四:快速判断两个值是否相等。
1 | if ((a ^ b) == 0) |
从上面的几个基本使用方法还可以衍生出一些高级的用法。
用法一:如异或的加密运算。
1 | #include <stdio.h> |
这里使用了异或取反的特点。用同一个密钥(在上面代码中为变量secret),对相同的位进行异或取反两次就可以得到原文。也就是负负得正的原理,“负”一次为密文,再“负”一次就是原文了。
用法二:检测两个数不同的比特位位置。
1 | int a = 0b10100001; |
根据结果我们可以看到数a和数b,第1位和第4位的比特位是不同的。当且仅当只有一个数的某位上为1时,结果的该位才为1。否则结果的该位为0。
用法三:数a需要改变多少个比特位才能得到数b。
这是上面用法的扩展。
1 | #include <stdio.h> |
在上面代码中,数a和数b异或的结果c为0b00001010 。结果c表示,数a需要根据数c,在数c比特位为1的对应位置取反,就可以得到数b。具体到上面的代码中,数a需要在第1位和第4位的位置取反,就可以得到数b。而代码中while循环和其中count的意思是,数a需要改变2个比特位才能得到数b。