位操作学习
位操作学习
位操作是程序设计中对位模式或二进制数的一元和二元操作,位运算比加减运算速度略快,通常位运算比乘除运算要快很多。
取反(NOT)
取反是一元运算符,对一个二进制数的每一位执行逻辑反操作,使数组1变成0,使0变成1。例如:
NOT 0001(十进制7)
= 1000(十进制8)
许多的程序语言中,取反操作符用的是~
表示,此操作符与逻辑非操作符不同,在c++中,逻辑非将数组整体看作一个bool类型——将真值转为假值,将假值转化为真值,而c语言将0转化为1,将非零值转化为0,逻辑非并不是一个位操作。
按位或(OR)
按位与处理两个长度相同的二进制数,两个相应的二进制中只要有一个为1,该位的结果值为1。
0101
OR 0011
= 0111
按位或能够将每一位看作旗标,在二进制书中的每一位可以表示不同的布尔变量,使用按位或操作可以将二进制数的某一位设为1。这一技巧通常用来保存大量的布尔变量。
按位异或(XOR)
按位异或运算,对于长二进制模式或者二进制数的每一位执行逻辑异或操作,操作的结果是如果某位不同则该位为一,否则该位为0。
0101
XOR 0011
= 0110
在汇编语言中可以使用按位异或作为寄存器的值设为0的捷径。
按位异或也可以用于在比特集合中切换旗标,这一技巧可用于操作布尔变量的比特模式。
按位与(AND)
按位与处理两个长度相同的二进制数,两个相应的二进制数都为1,则该位的结果为1,否则为零。
0101
AND 0011
= 0001
移位
移位是一个二元运算符,用来将一个二进制数中的每一位全部向一个方向移动指定位,溢出的部分将会被舍弃,而空缺的部分填入一定的值。
可以进行移位的数据类型:
char、short、int、long、unsigned char、unsigned short、unsigned int、unsigned long
不可以进行移位的数据类型:
double、float、bool、long double
逻辑移位
对于逻辑移位,就是不考虑符号位,移位的结果只是数据所有的位数进行移位。根据移位操作的目的,左移时,低位补0,右移时,高位补0
算术移位
算术是带有符号的数据,所以我们直接移动所有的位数,这可能会使得符号不正确。
关于数的移位,特别需要注意正数,三码相同,所以无论左移还是右移都是补0.而负数的补码就需要注意,左移在右边补0,右移需要在左边补1,有一个很有趣的误区是,认为符号位保持不变,仅仅移动数据位,这是不对的,因为无论数据位还是符号位,都是二进制,在整体大迁移的过程中,符号位也是要跟随潮流的。只不过,为了保证右移后,和原来的符号数一样,因此,负数在右移时左边补1.
常见的位运算问题
1、位运算实现乘除法
一个数向右移一位相当于除以2,向左移相当于乘以2
2、位操作交换两数
位操作交换两数可以不需要第三个临时变量,虽然普通操作也可以做到,但是没有其效率高
//普通交换
void swap(int& a,int& b)
{
a = a + b;
b = a - b;
a = a - b;
}
//异或操作
void swap(int& a,int& b)
{
if(a != b)
{
a ^= b;
b ^= a;
a ^= b;
}
}
3、位操作统计二进制中 1 的个数
count = 0
while(a){
a = a & (a - 1);
count++;
}