What about:
int bitset(unsigned short s)
{
int lookup[] = {16, 1, 11, 2, 14, 12, 3, 6, 15, 10, 13, 5, 9, 4, 8, 7};
return lookup[(((int) s*0x6F28)>>14)&15];
}
Test:
int main(void)
{
int i, j;
for (i = j = 1; i <= 16; ++i, j <<=1)
{
printf("for %5d, the %3dth bit is set\n", j, bitset(j));
}
return 0;
}
Gives:
for 1, the 1th bit is set
for 2, the 2th bit is set
for 4, the 3th bit is set
for 8, the 4th bit is set
for 16, the 5th bit is set
for 32, the 6th bit is set
for 64, the 7th bit is set
for 128, the 8th bit is set
for 256, the 9th bit is set
for 512, the 10th bit is set
for 1024, the 11th bit is set
for 2048, the 12th bit is set
for 4096, the 13th bit is set
for 8192, the 14th bit is set
for 16384, the 15th bit is set
for 32768, the 16th bit is set
Explanation
The first algorithm (8bits) is the following:
Build a unique number from power of two numbers (1, 2, 4...)
The incoming number s
can be decomposed in bits:
s7s6s5s4s3s2s1s0, for instance, s == 4 means s2 = 1, other = 0
One number is build summing the different sx:
This operation is done by the *
operation (0x1D is 11101b)
|s7s6s5s4|s3s2s1s0 // 1b
s7s6|s5s4s3s2|s1s0 0 0 // 100b
s7s6s5|s4s3s2s1|s0 0 0 0 // 1000b
s7s6s5s4|s3s2s1s0| 0 0 0 0 // 10000b
Look at the number between pipe: it's unique,
- if
s
is 1, the sum (between pipe) is 0b+0b+0b+1b = 1
- if
s
is 2, the sum (between pipe) is 0b+0b+1b+10b = 2
- if
s
is 4, the sum (between pipe) is 0b+1b+10b+100b = 7
- if
s
is 8, the sum (between pipe) is 0b+10b+100b+1000b = 14
and so
The >>
and &
operations make the selection of the 4 middles bits.
Finally, a simple lookup table is to be applied to the unique number to get the set bit.
The 16 bits algorithm is a generalisation of this, the difficulty has been to find a combination of bits that gives unique numbers for powers of two.