既然大家喜欢,就再发几个:
几个常用的位操作
下面的结论都是基于用补码表示负数的计算机平台
1 int main(unsigned int x)
2 {
3 //判断无符号整数x是否是2的幂
4 if(x&(x-1))//若一个数是2的幂,则除最高位为1外,其余位均为0(二进制表示,下同)
5 printf("False\n");
6 else
7 printf("True\n");
8
9 //判断一个无符号整数是否为2^n-1的形式(原理同上)
10 if(x&(x+1))//若为2^n-1,则低位全为1
11 printf("False\n");
12 else
13 printf("True\n");
14
15 //整数能被最大的2的幂(?)整除 : 析出最右侧为1的位
16 //e.g.: 100->4
17 printf("%d\n",x&(-x));//将其余位置0
18
19 //析出最右侧为0的位(原理同上)
20 //e.g.:111b->1000b, 10->1
21 printf("%d\n",~x&(x+1));//将该位置1,其余位置0
22
23 //识别后缀0的掩码(将右侧连续的0位置1,其余各位置0)
24 //e.g.:1100b->0011b
25 printf("%d\n", ~x&(x-1)); //或
26 printf("%d\n", ~(x|-x)); //或
27 printf("%d\n", (x&-x)-1);
28
29 //识别最右侧的1未和后缀0的掩码(将最右侧的1位保留,并将其后面所有的0位置1)
30 //e.g.:1100b->0111b
31 printf("%d\n", x^(x-1));
32
33 //向右传播最右侧的1位
34 //e.g.:1100b->1111b
35 printf("%d\n", x|(x-1));
36
37 //将最右侧连续的1位置0
38 //e.g.:10110b->10000
39 printf("%d\n", ((x|(x-1))+1)&x);
40 }
计算x中有多少个为1的位:
1 int Count1(int x)
2 {
3 int n = 0;
4 while(x)
5 {
6 n++;
7 x&=x-1;
8 }
9 return n;
10 }
获取下一个具有同样数量的1位的更大的数;应用:在用位串表示集合的子集时
1 unsigned snoob(unsigned x)
2 {
3 unsigned smallest, ripple, ones;//e.g.: x=XXX0 1111 0000
4 smallest = x & -x; // 0000 0001 0000
5 ripple = x + smallest; // XXX1 0000 0000
6 ones = x ^ ripple; // 0001 1111 0000
7 ones = (ones >> 2) / smallest; // 0000 0000 0111
8 return ripple | ones; // XXX1 0000 0111
9 }