An 8-bit value has 8 digits.
int lsb_pos(std::uint8_t v) { // 1. Define a De Bruijn Bit Table. static constexpr int DeBruijnBitTable[8] = { 1 , 2 , 7 , 3 , 8 , 6 , 5 , 4 }; // 2. Get the LSB. std::uint8_t pop_lsb = (v & -v); // 3. Get which Index to use in the De Bruijn Bit Table. std::uint8_t hash = std::uint8_t (pop_lsb * 0x1DU) >> 5; // 4. Get the specific Table value. int r = DeBruijnBitTable[hash]; return r; }
NOTE: This shows 4 steps:
The big question is where do the following come from:
* 000 001 011 111 110 101 010 100
bit | pop_lsb | pop_lsb * 0x1D | hash | index | index order | final order |
---|---|---|---|---|---|---|
(1st 3 bits) | (index + 1) | (bit at index order position) | ||||
1 | 1 | 0001 1101 | 000 | 0 | 1 | 1 |
2 | 2 | 0011 1010 | 001 | 1 | 2 | 2 |
3 | 4 | 0111 0100 | 011 | 3 | 4 | 3 |
4 | 8 | 1110 1000 | 111 | 7 | 8 | 7 |
5 | 16 | 1101 0000 | 110 | 6 | 7 | 6 |
6 | 32 | 1010 0000 | 101 | 5 | 6 | 5 |
7 | 64 | 0100 0000 | 010 | 2 | 3 | 7 |
8 | 128 | 1000 0000 | 100 | 4 | 5 | 4 |
NOTE: This is a complete hash in which a value with only one bit set is nicely pushed into a 3-bit number.
constexpr int table [8] = { 1 , 2 , 7 , 3 , 8 , 6 , 5 , 4 };
constexpr int table [8] = { 1 , 2 , 7 , 3 , 8 , 6 , 5 , 4 };
The c++ code above performs the following function.
Lookup | Lookup multiple by the magic number | Right-shifted by the offset |
---|---|---|
(29 in this example) | (5 in this example) | |
1 | 29 | 0 |
2 | 58 | 1 |
7 | 203 | 6 |
3 | 87 | 2 |
8 | 232 | 7 |
6 | 174 | 5 |
5 | 145 | 4 |
4 | 116 | 3 |
NOTE: This shows that:
Every lookup returns a unique and distinct value.
NOTE: Here, the 1D magic number was used.
hash(x) = (x ∗ dEBRUIJN) >> SHIFT
NOTE: