Update: .NET Core 3.0 introduced BitOperations.LeadingZeroCount()
and BitOperations.Log2()
which map directly to the underlying CPU's bitwise leading zero count instruction, hence extremely efficient
public static uint highestOneBit(uint i)
{
return i == 0 ? 0 : 1 << BitOperations.Log2(i); // or
// return i == 0 ? 0 : 1 << (31 - BitOperations.LeadingZeroCount(i));
}
This is basically round down to the next power of 2 and there are so many ways to do that in the famous bithacks site. The implementations there is for rounding up to the next power of 2 so just shift right by 1 to get what you want
public static uint highestOneBit(uint i)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++; // now v is the next power of 2
v >>= 1; // get the previous power of 2
}
Another way:
public static uint highestOneBit(uint v)
{
const int MultiplyDeBruijnBitPosition[32] =
{
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return 1 << MultiplyDeBruijnBitPosition[(v*0x07C4ACDDU) >> 27];
}