Assuming you know the size of the int in question (e.g., 32 bits) you can pretty easily use a binary search for the highest bit that's set:
int bit_pos(unsigned value) {
static const std::vector<unsigned> masks = {
0xffff0000,
0xff00ff00,
0xf0f0f0f0,
0xcccccccc,
0xaaaaaaaa
};
if (!value)
return 0;
int position = 0;
int val = 16;
for (unsigned mask : masks) {
if (value & mask) {
position += val;
value &= mask;
}
val /= 2;
}
return position + 1;
}
For (probably) a little extra speed at the expense of even greater obscurity, you can do a little bit extra fiddling up front to get only one bit set, then find its position:
unsigned bit_pos2(unsigned int value) {
unsigned int position = 32;
value = ~value;
value &= -signed(value);
if (value) --position;
if (value & 0x0000ffff) position -= 16;
if (value & 0x00ff00ff) position -= 8;
if (value & 0x0f0f0f0f) position -= 4;
if (value & 0x33333333) position -= 2;
if (value & 0x55555555) position -= 1;
return position;
}
For 64-bit integers, the numbers get larger, but we need to add only one more iteration:
unsigned bit_pos64(unsigned long long value) {
value = ~value;
unsigned position = 64;
value &= -(long long)value;
if (value) --position;
if (value & 0x00000000ffffffff) position -= 32;
if (value & 0x0000ffff0000ffff) position -= 16;
if (value & 0x00ff00ff00ff00ff) position -= 8;
if (value & 0x0f0f0f0f0f0f0f0f) position -= 4;
if (value & 0x3333333333333333) position -= 2;
if (value & 0x5555555555555555) position -= 1;
return position;
}
By having only one bit set, we avoid dependencies between the loop iterations, so the iterations can be executed in parallel. Manually unrolling the loop (as above) may help the chances of that happening, at least slightly. This also requires only one operation per iteration instead of 2, so it may be faster even without any parallel execution.