值为1且最靠右的位元置为0 (如果存在): 0101 1110 => 010 1100 : x&(x-1)
值为0且最靠右的位元置为1 (如果存在): 0101 1110 => 010 1111 : x|(x+1)
将尾部的所有连续的1置为0(如果存在): 0101 0111 => 0101 0000 : x&(x+1)
将尾部的所有连续的0置为1(如果存在): 0101 1000 => 0101 1111 : x|(x-1)
将最靠右的0置为1(如果存在),且其他位元置为0: 0101 0111 => 0000 1000 : ~x&(x+1)
将最靠右的1置为0(如果存在),且其他位元置为1: 0101 1000 => 1111 0111 : ~x|(x-1)
将尾部的连续0置为1(如果存在),且其他位元置为0: 0101 1000 => 0000 0111 : ~x&(x-1) or ~(x|-x) or (x&-x)-1
将尾部的连续1置为0(如果存在),且其他位元置为1: 0101 0111 => 1111 1000 : ~x|(x+1)
保留最右的1(如果存在),其他位元置为1: 0101 1000 => 0000 1000 :x&(-x)
最靠右的1及其右边的位元置为1,左边置为0: 0101 1010 => 0000 1111 : x^(x-1)
最靠右的0及其右边的位元置为1,左边置为0: 0101 1010 => 0000 0111 : x^(x+1)
右侧首个连续的1置为0: 0101 1100 => 0100 0000 (((x|(x-1))+1&x) or ((x&-x)+x)&x
进阶:
求比某个数大且位元1的个数相同的数 例如 xxx0 1111 0000 => xxx1 0000 0111
令 x = xxx0 1111 0000
s = x&-x
r = s+x
y = r | ( ( x ^ r ) << 2 / s)
两数的平均数:
(x&y) + ((x^y)>>1) 下取整
(x|y) – ((x^y)>>1) 上取整
统计位元‘1’的个数:
1.二分搜索法:
x = (x & 0x5555 5555) + ((x>>1) & 0x5555 5555)
x = (x & 0x3333 3333) + ((x>>2) & 0x3333 3333)
x = (x & 0x0F0F 0F0F) + ((x>>4) & 0x0F0F 0F0F)
x = (x & 0x00FF 00FF) + ((x>>8) & 0x00FF 00FF)
x = (x & 0x0000 FFFF) + ((x>>16) & 0x0000 FFFF)
例举一个八位数:
x = 1 0 1 1 1 1 0 0
x1 = 01 10 10 00
x2 = 0011 0010
x3 = 00000101 = 5
上述代码中有多余的与操作
可以写成如下简单代码:
int pop(unsigned x){
x = x – ((x>>1) & 0x5555 5555)
x = (x & 0x3333 3333) + ((x>>2) & 0x3333 3333)
x = (x+(x>>4)) & 0x0F0F 0F0F
x = x+(x>>8)
x = x + (x>>16)
return x& 0x0000 003F
}
第一行中x的值是由以下公式而来:
pop(x) = x – [x/2] – [x/4]-···-[x/2^31]