Hacker's Delight #0001 Operating right end bits
ref. Hacker’s Delight (English / Japanese)
Unset rightmost set bit
e.g. 01011000 -> 01010000
x & (x - 1)
The bits start from rightmost set bit are 10*. (The * means repeat character more than 0.)
The reverse bits of 10* is 01*.
The 01* is derived from 10* - 1.
0101 1000 (x)
AND 0101 0111 (x-1)
-> 0101 0000
If x & (x - 1) is zero, the x is 2^n.
(The 2^n has just one set bit.)
2^n - 1
x & (x + 1)
If x & (x + 1) is zero, the x is 2^n - 1.
0 = x & (x + 1)
0 = (2^n - 1) & (2^n)
0 = 01{n} & 10{n}
01...
AND 10...
-> 00...
(The {n} means repeat character exactly n times.)
Extract rightmost set bit
e.g. 01011000 -> 00001000
x & (-x)
The minus values is two’s complement.
The operations to generate two’s complement:
- Reverse all bits
- +1
The reverse operation generates ...01*.
The +1 operation generates ...10*.
0101 1000
AND 1010 1000
-> 0000 1000
Set only rightmost unset bit
e.g. 10100111 -> 00001000
^x & (x + 1)
The bits start from rightmost unset bit are 01*.
And, 01* plus 1 is 10*.
The ^x makes {reversed bits}10*.
1010 1000
AND 0101 1000
-> 0000 1000
The mask for trailing zeros
e.g. 01011000 -> 00000111
A
^x & (x - 1)
Subtract 1 from 10* is 01*.
The ^x makes {reverse bits}01*.
10100111
AND 01010111
-> 00000111
B
^(x | -x)
The two’s complement makes {reverse bits}10*.
The OR operation makes 1*0*.
01011000
OR 10101000
-> 11111000
NOT 11111000
-> 00000111
C
(x & -x) - 1
The (x & -x) is way for extract rightmost set bit.
01011000 (x & -x)
-> 00001000
00001000 (-1)
-> 00000111
The mask for bits start from rightmost set bit
e.g. 01011000 -> 00001111
x ^ (x - 1)
The -1 operation reverse bits start from rightmost set bit.
01011000
XOR 01010111
-> 00001111
Set bits after rightmost set bit
e.g. 01011000 -> 01011111
x | (x - 1)
01011000
OR 01010111
-> 01011111
Unset rightmost sequential 1
e.g. 01011000 -> 01000000
((x | (x - 1) + 1)) & x
The x | (x - 1) makes set bits start from rightmost set bit.
The +1 reverse sequential 1 bits.
01011000
01010111
OR 01011111 x | (x - 1)
01011111
-> 01100000 + 1
01100000
AND 01011000
-> 01000000
If ((x | (x - 1) + 1)) & x is zero, the x is 2^j - 2^k (j >= k >= 0).
The both 2^j and 2^k have just one set bit.
So, 2^j - 2^k makes 0*1*0*.
Set rightmost unset bit
e.g. 10100111 -> 10101111
x | (x + 1)
The bits start from rightmost unset bit are 01*.
And, 01* plus 1 is 10*.
1010 0111
-> 1010 1000 (+1)
1010 0111
OR 1010 1000
-> 1010 1111
Iterate same size subsets
e.g. xxx011110000 -> xxx100000111 -> …
s <- x & -x
r <- s + x
y <- r | (((x ^ r) >> 2) / s)
unsigned snoob(unsigned x) {
unsigned smallest, ripple, ones; // xxx0 1111 0000
smallest = x & -x; // 0000 0001 0000
ripple = x + smallest; // xxx1 0000 0000
ones = x ^ ripple; // 0001 1111 0000
ones = (ones >> 2) / smallest; // 0000 0000 0111
return ripple | ones; // xxx1 0000 0111
}