a&1 = 0 偶数
a&1 = 1 奇数
if((a & 1)==0) {
//偶数
}
第一次:计算前:1000 0110 1101 1000 计算后:1000 0110 1101 0000
第二次:计算前:1000 0110 1101 0000 计算后:1000 0110 1100 0000
第三次:计算前:1000 0110 1100 0000 计算后:1000 0110 1000 0000 我们发现,没计算一次二进制中就少了一个 1,则我们可以通过下面方法去统计:
count = 0
while(a){
a = a & (a - 1);
count++;
}
让a对k进行取余,那么就可以让 a & (k-1)
3%2=1
||
3&(1)=1
0011
&0001
----------
0001
boolean power2(int x)
{
return ((x&(x-1))==0)&&(x!=0);
}
a % (2^n) 等价于 a & (2^n - 1)
对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的。
int average(int x, int y) //返回X,Y 的平均值
{
return (x&y)+((x^y)>>1);
}
(1)清0公式:
内容 | 公式 |
---|---|
1.将某个数据A的第n位清0,其它位保持不变: | A &= ~(0x1 << n); |
2.将某个数据A从第n位开始,连续两个bit位清0,其它位保持不变: | A &= ~(0x3 << n); |
3.将某个数据A从第n位开始,连续三个bit位清0,其它位保持不变: | A &= ~(0x7 << n); |
4.将某个数据A从第n位开始,连续四个bit位清0,其它位保持不变: | A &= ~(0xF << n); |
5.将某个数据A从第n位开始,连续五个bit位清0,其它位保持不变: | A &= ~(0x1F << n); |
6.将某个数据A从第n位开始,连续六个bit位清0,其它位保持不变: | A &= ~(0x3F << n); |
7.将某个数据A从第n位开始,连续七个bit位清0,其它位保持不变: | A &= ~(0x7F << n); |
8.将某个数据A从第n位开始,连续八个bit位清0,其它位保持不变: | A &= ~(0xFF << n); |
(2)置1公式
内容 | 公式 |
---|---|
将某个数据A的第n位置1,其它位保持不变: | A |
2.将某个数据A从第n位开始,连续两个bit位置1,其它位保持不变: | A |
3.将某个数据A从第n位开始,连续三个bit位置1,其它位保持不变: | A |
4.将某个数据A从第n位开始,连续四个bit位置1,其它位保持不变: | A |
5.将某个数据A从第n位开始,连续五个bit位置1,其它位保持不变: | A |
6.将某个数据A从第n位开始,连续六个bit位置1,其它位保持不变: | A |
7.将某个数据A从第n位开始,连续七个bit位置1,其它位保持不变: | A |
8.将某个数据A从第n位开始,连续八个bit位置1,其它位保持不变: | A |
性质:
a^a=0
a^0=a
a^b^a=b
//普通操作
void swap(int &a, int &b) {
a = a + b;
b = a - b;
a = a - b;
}
//位与操作
void swap(int &a, int &b) {
a ^= b;
b ^= a;
a ^= b;
}
if (x == a)
x= b;
else x= a; 等价于 x= a ^ b ^ x;
a * (2^n) 等价于 a<< n
对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的。
int average(int x, int y) //返回X,Y 的平均值
{
return (x&y)+((x^y)>>1);
}
将无符号数 a>>8 即可得到其高 8 位移到低 8 位,高位补 0;将 a<<8 即可将 低 8 位移到高 8 位,低 8 位补 0,然后将 a>>8 和 a<<8 进行或操作既可求得交换后的结果。
a = (a >> 8) | (a << 8);
在字符串逆序过程中,可以从字符串的首尾开始,依次交换两端的数据。在二进制中使用位的高低位交换会更方便进行处理,这里我们分组进行多步处理。
第一步:以每 2 位为一组,组内进行高低位交换
交换前: 10 00 01 10 11 01 10 00
交换后: 01 00 10 01 11 10 01 00
第二步:在上面的基础上,以每 4 位为 1 组,组内高低位进行交换
交换前: 0100 1001 1110 0100
交换后: 0001 0110 1011 0001
第三步:以每 8 位为一组,组内高低位进行交换
交换前: 00010110 10110001
交换后: 01100001 00011011
第四步:以每16位为一组,组内高低位进行交换
交换前: 0110000100011011
交换后: 0001101101100001
对于上面的第一步,依次以 2 位作为一组,再进行组内高低位交换,这样处理起来比较繁琐,下面介绍另外一种方法进行处理。
先分别取原数 10000110 11011000 的奇数位和偶数位,将空余位用 0 填充:
原数: 10000110 11011000
奇数位: 10000010 10001000
偶数位: 00000100 01010000
再将奇数位右移一位,偶数位左移一位,此时将两个数据相或即可以达到奇偶位上数据交换的效果:
原数: 10000110 11011000
奇数位右移一位: 0 10000010 1000100
偶数位左移一位:0000100 01010000 0
两数相或得到: 01001001 11100100
上面的方法用位操作可以表示为:
取a的奇数位并用 0 进行填充可以表示为:a & 0xAAAA
取a的偶数为并用 0 进行填充可以表示为:a & 0x5555
因此,上面的第一步可以表示为:a = ((a & 0xAAAA) >> 1) | ((a & 0x5555) << 1)
同理,可以得到其第二、三和四步为:
a = ((a & 0xCCCC) >> 2) | ((a & 0x3333) << 2)
a = ((a & 0xF0F0) >> 4) | ((a & 0x0F0F) << 4)
a = ((a & 0xFF00) >> 8) | ((a & 0x00FF) << 8)
因此可总结为:
unsigned short a = 34520;
a = ((a & 0xAAAA) >> 1) | ((a & 0x5555) << 1);
a = ((a & 0xCCCC) >> 2) | ((a & 0x3333) << 2);
a = ((a & 0xF0F0) >> 4) | ((a & 0x0F0F) << 4);
a = ((a & 0xFF00) >> 8) | ((a & 0x00FF) << 8);
a / (2^n) 等价于 a>> n
例: 12/8 == 12>>3
a>>k&1
将无符号数 a>>8 即可得到其高 8 位移到低 8 位,高位补 0;将 a<<8 即可将 低 8 位移到高 8 位,低 8 位补 0,然后将 a>>8 和 a<<8 进行或操作既可求得交换后的结果。
a = (a >> 8) | (a << 8);
交换符号将正数变成负数,负数变成正数
int reversal(int a) {
return ~a + 1;
}
整数的绝对值是其本身,负数的绝对值正好可以对其进行取反加一求得。
即我们首先判断其符号位(整数右移 31 位得到 0,负数右移 31 位得到 -1,即 0xffffffff),然后根据符号进行相应的操作。
int abs(int a) {
int y = a >> 31;
return y== 0 ? a : (~a + 1);
}