0000 => 0000
0001 => 1111
0010 => 1110
0100 => 1100
1000 => 1000
此外:
0101 => 1101
正如你所看到的,我需要在最后一次' 1之后填写#1;但我事先并不知道最后一个' 1' ;是
答案 0 :(得分:1)
也许像
unsigned int data;
unsigned int copy = data;
unsigned int shifts = 0;
while (copy > 0) {copy=copy>>1; ++shifts;};
data = data|((1<<shifts)-1);
答案 1 :(得分:1)
不是直接制作必须打开的位掩码,而是更容易制作应该保持不变的位掩码(不是真的,但这样更容易解释) ):将最左边的1复制到右边的所有位:
m = x | (x >> 1);
m |= m >> 2;
m |= m >> 4;
m |= m >> 8;
m |= m >> 16; // 5 steps for 32 bits, in general log2(width) steps
例如,0101 => 0111
或1000 -> 1111
。
显然,补码是应该打开的位掩码(除非x
为零),所以现在:
if (x != 0) // this line makes me sad :(
x |= ~m;
避免长循环,但仍然有一部分不严格的位操作。
不太清楚,使用我的评论中的技巧,观察如果m
只有最左边的1个集合,它的否定将是必须在x
中设置的位(并且有点已在x
中设置,但没关系。所以你得到:
m &= ~(m >> 1); // see below
x |= -m;
m &= ~(m >> 1)
技巧只占m
中最左边的1个,这是可能的,因为m
是2减1的幂,所以唯一的1可以有0到0它的左边是最左边的1.对于x = 0
,m = 0
,因此显然是m & something = 0
- 不需要特殊情况。在x
设置了最高位并因此m = -1
的情况下,虽然最左边的1左边没有零,但是它仍会被右移移入(确保它&#39 ;逻辑移位,而非算术移位)。