基础:
或运算 | ,逻辑代数中使用+ 或0, 保持;或1,置1;而且同时为0,结果才为0;
与运算&,逻辑代数中使用 . 与1,保持;与0,清0;而且同时为1,结果才为1.
异或运算^, 逻辑代数中使用^; 异或0,保持;异或1,取反。
三种逻辑运算,都有一种保持;剩下的刚好分别是清0,置1,取反。
+和*是对偶的(在分配律下看出)。相同运算符的运算,满足交换律和结合律。
对于两个数,a | b用来标记a,b中同时为0的位;a & b用来标记a , b中同时为1的为位;a ^ b用来标记a, b中不同的位。
1、交换两个数
1、a=a^b ; 2、b =a^b; 3、a = a^b
2中的a实际上是原始的a^b, a^b^b = a^(b^b) = a^0 =a; 即b =a(最初的a); 3式中的b是原来的a, (a^b)^b = a; 所以将变化的a 还原为原来的a。
2、判断是否是偶数
只需要判断最后一位是0还是1,这样把前边所有为置0(与0),最后一位保持不变(与1),与运算刚好可以。
a&1 = 0 偶数
a&1 = 1 奇数
3、第k位清0
类似的的将第k位清0,其他位保持不变,可以与上一个第k位为0,其他位为1的数。得到一个第k位为0的数,其他位为1的数,可以从一的第k位为1,其他位为0的数按位取反得到。后者可以通过1的左移k位实现。
最终实现:
a=a&~(1<<k)
4、第k位置1
第k位置1(或1),其他位不变(或0),可以或上一个第k位为1,其他位为0的数。
最终实现:
a=a|(1<<k)
5、第k位取反
第k位取反(异或1),其他位不变(异或0),可以异或上一个第k位为1,其他位为0的数。
a=a^(1<<k)
6、循环移位
由于不同编译器对于 >> 实现为算术右移还是逻辑右移(算术右移最高位补符号位,逻辑右移最高位补0)的处理不同,所以下边的只对逻辑右移和无符号数成立,假设a是32位整数。
循环左移k位
a=a<<k|a>>32-k
循环右移k位
a=a>>k|a<<32-k
7、将最右边的1清0
清0自然是与0,保持由于并不知道哪些位是1,所以不能通过与1实现,不过可以用与本身来保持;减1 将最右边的1之后的所有位(全部是0)取反(变成全部1),1的那位变成0,也就是说,刚好减1之后,从最右边的1那位开始,全部取反。A&~A = 0;
应用,将最左边的1清0之后,判断其是否为0来判断是否是2的幂。
a=a&(a-1)
8、将最右边的0置1
类似的,加上1将最右边的0开始的所有位取反,A | ~A = 1;
a=a|(a+1)
9、位运算实现加法和乘法
加法:同时为位0可以不考虑;同时为1的位的和用 x&y标记,然后进位用左移1位实现,得到结果x1;相异位和用x^y实现,结果为y1;重复,知道最终结果进位为0,结果即为yn。描述上用递推最好实现。
x + y=(x&y<<1) + x^y
乘法:a 乘以 2^n相当于 a<< n; 将b从最低位开始,如果是1, 将a左移对应的位数;将乘法转化为加法实现。
10、求相反数
由于一个数和其按位取反之后的和为全1 , 所以a的相反数的表示为(计算机表示):
~a+1
实际上, 由于计算机内全是补码, 补码的加法需带符号位进行, 如果符号位向前有进位, 舍弃进位 . 对于负数补码的求法, 就是其对应正整数的相反数.