什么是位?
简单来说,位就是1和0,在电脑中做的每一件事都是由它们组成的。电脑中所有的数据使用的是位。一个字节由8个位组成;一个字由两个字节组成,即16个位;而一个双字由四个字节组成,即32个位。由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快
位运算有哪些操作符?
& ,| ,~,<<,>>,^
(补充,逻辑运算符是 || , && , !这些和位运算符大大不同)
它们分别的意思是:
& 与运算符 | 或运算符 ~ 取反运算符 >> 右移运算符 << 左移运算符 ^ 异或运算符
下面我们看看这些操作符是怎么操作的:
&:
(1).运算规则:有0变0,无0为1
(2).判断奇偶性
a&1 = 0 偶数
a&1 = 1 奇数
(3).可以用来取位操作
如:一个数 and 1的结果就是取二进制的最末位
(4).判断一个数的二进制第n位是否为1的方法是:把一个n位为1,其它位为0与待判断的数进行与运算
我们看下例子(看是否存在D盘,主要是根据与运算是否存在1000):
DWORD d = GetLogicalDrives(); if((d&8)>0) //是否存在D盘 { SetDlgItemText(hwnd,IDC_EDTNAME4,TEXT("存在D盘")); } else { SetDlgItemText(hwnd,IDC_EDTNAME4,TEXT("不存在D盘")); }
(5).求余优化(x%(2n)=x&(2n-1))
| (或)
(1).运算规则:有1变1,无1变0
(2).一个数or 1的结果就是把二进制最末位强行变成1
~(取反)
(1).取反运算的定义是把内存中的0和1全部取反。使用not运算时要格外小心,你需要注意整数类型有没有符号。如果not的对象是无符号整数(不能表示负数)。
如:
#include <stdio.h> int main(void) { unsigned short a=100; a = ~a; printf( "%d/n", a ); return 0; }
如上面的一段程序 算出来为 65435 而它的上界位65536 所以算出来的结果是它们的差,因为无符号类型的数是用$0000到$FFFF依次表示的。
<<(左移)
(1).如A<<B:是A转换为二进制后向左移动B位
(2).左移3相当于乘以2的3次方
可以使用(1 << 16 )-1来表示个常量 如#defien Max_N (1 << 16 )-1, 因为这个值表示65535(很有用,有时大量的乘除运算可用移位代替,效率会很高!)
>>(右移)
(1).A>>B:是A转换为二进制后向右移动B位
(2).右边的位被挤掉。对于左边移出的空位,如果是正数则空位补0,若为负数,可能补0或补1,这取决于所用的计算机系统。
(3).右移3相当于除以2的3次方
下面是个例子,看电脑中存在多少磁盘(主要是右移!)
void countIt(HWND hwnd) { DWORD n = GetLogicalDrives(); int count = 0;//计数器 while(n>0) { if((n&1)>0)//判断最后一位是否为1 { count ++; } n = n>>1;//继续右移 } TCHAR cD[256]; itoa(count,cD,10); MessageBox(NULL,cD,TEXT("hello!"),MB_OK); }
^:(异或)
1.可以用一句话理解:是不是不一样 (不一样为1,一样为0)
2.两次异或同一个数还是它本身(如:(a ^b)^b=a)
3.(a ^ b) ^ b = a,像这种异或运算可用于加密 用两次异或 b位密码
4.另外还有一个是不引入第三变量,交换两个变量的值 (设 a=a1,b=b1)
5.两个二进制数异或的结果为两者之差的绝对值
一些位运算的例子:
功能 | 示例 | 位运算 ----------------------+---------------------------+-------------------- 去掉最后一位 | (101101->10110) | x >> 1 在最后加一个0 | (101101->1011010) | x << 1 在最后加一个1 | (101101->1011011) | x << 1+1 把最后一位变成1 | (101100->101101) | x | 1 把最后一位变成0 | (101101->101100) | x | 1-1 最后一位取反 | (101101->101100) | x ^ 1 把右数第k位变成1 | (101001->101101,k=3) | x | (1 <<(k-1)) 把右数第k位变成0 | (101101->101001,k=3) | x & ~ (1 << (k-1)) 右数第k位取反 | (101001->101101,k=3) | x ^ (1 << (k-1)) 取末三位 | (1101101->101) | x & 7 取末k位 | (1101101->1101,k=5) | x & (1 << k-1) 取右数第k位 | (1101101->1,k=4) | x >> (k-1) & 1 把末k位变成1 | (101001->101111,k=4) | x | (1 << k-1) 末k位取反 | (101001->100110,k=4) | x ^ (1 << k-1) 把右边连续的1变成0 | (100101111->100100000) | x & (x+1) 把右起第一个0变成1 | (100101111->100111111) | x | (x+1) 把右边连续的0变成1 | (11011000->11011111) | x | (x-1) 取右边连续的1 | (100101111->1111) | (x ^ (x+1)) >> 1 去掉右起第一个1的左边 | (100101000->1000) | x & (x ^ (x-1))
位运算求绝对值:
x >> 31是二进制的最高位,它用来表示x的符号。如果它为0(x为正),则~ (x >> 31) + 1等于$00000000,异或任何数结果都不变;如果最高位为1(x为负),则~ (x >> 31) + 1等于$FFFFFFFF,x异或它相当于所有数位取反,异或完后再加1。