Not too happy with the answers on here, I thought I'd give this one a go myself.
Returns 0 if 0 is passed in or index of the bit + 1, for all other values. Handles signed and unsigned values. Is template for completeness.
template<typename T>inline T ones_mask(unsigned cnt) { return ~(~static_cast<T>(0) << cnt);}template<typename T>unsigned most_significant_one_bit_position(T val) { //returns 1's index of most significant one bit position, zero returned for zero //finds the closest fitting half interval, near optimal half interval search!!! if(val == 0) return 0; //do half interval search unsigned rslt = sizeof(T) * 8; unsigned interval = (sizeof(T) * 8) >> 1; unsigned mask_size = (sizeof(T) * 8) >> 1; //while halfing the interval is non zero do { bool found = (ones_mask<T>(mask_size) & val) == val; //if we have found a matching mask, record this size as the result rslt = (found ? mask_size : rslt); //half the interval here interval >>= 1; //increase or decrease the mask size depending on if we found a match mask_size += (found ? -interval : interval); } while(interval > 0); return rslt;}
A slightly more optimal version, that doesn't make a ones mask, can be found below (still not C code).
#include <type_traits>template<typename T>unsigned most_significant_one_bit_position(T val) { using unsigned_type = std::make_unsigned_t<T>; //returns 1's index of most significant one bit position, zero returned for zero //finds the closest fitting half interval, near optimal half interval search!!! if(val == 0) return 0; auto nval = static_cast<unsigned_type>(val); //do half interval search unsigned rslt = sizeof(T) * 8; unsigned interval = (sizeof(T) * 8) >> 1; unsigned mask_size = (sizeof(T) * 8) >> 1; //while halfing the interval is non zero do { bool found = (nval >> mask_size) == 0; //if we have found a matching mask, record this size as the result rslt = (found ? mask_size : rslt); //half the interval here interval >>= 1; //increase or decrease the mask size depending on if we found a match mask_size += (found ? -interval : interval); } while(interval > 0); return rslt;}
For the sake of completeness, I decided to make a C version:
unsigned most_significant_one_bit_position_inner(unsigned long long nval, unsigned szeof) { //returns 1's index of most significant one bit position, zero returned for zero //finds the closest fitting half interval, near optimal half interval search!!! if(nval == 0) return 0; //do half interval search unsigned rslt = szeof * 8; unsigned interval = (szeof * 8) >> 1; unsigned mask_size = (szeof * 8) >> 1; //while halfing the interval is non zero do { char found = (nval >> mask_size) == 0; //if we have found a matching mask, record this size as the result rslt = (found != 0 ? mask_size : rslt); //half the interval here interval >>= 1; //increase or decrease the mask size depending on if we found a match mask_size += (found != 0 ? -interval : interval); } while(interval > 0); return rslt;}unsigned most_significant_one_bit_position_uchar(unsigned char val) { return most_significant_one_bit_position_inner(val, sizeof(unsigned char));}unsigned most_significant_one_bit_position_ushort(unsigned short val) { return most_significant_one_bit_position_inner(val, sizeof(unsigned short));}unsigned most_significant_one_bit_position_uint(unsigned val) { return most_significant_one_bit_position_inner(val, sizeof(unsigned));}unsigned most_significant_one_bit_position_ulong(unsigned long val) { return most_significant_one_bit_position_inner(val, sizeof(unsigned long));}unsigned most_significant_one_bit_position_ulonglong(unsigned long long val) { return most_significant_one_bit_position_inner(val, sizeof(unsigned long long));}unsigned most_significant_one_bit_position_schar(signed char val) { unsigned char nval = (unsigned char)val; return most_significant_one_bit_position_inner(nval, sizeof(signed char));}unsigned most_significant_one_bit_position_short(short val) { unsigned short nval = (unsigned short)val; return most_significant_one_bit_position_inner(nval, sizeof(short));}unsigned most_significant_one_bit_position_int(int val) { unsigned int nval = (unsigned int)val; return most_significant_one_bit_position_inner(nval, sizeof(int));}unsigned most_significant_one_bit_position_long(long val) { unsigned long nval = (unsigned long)val; return most_significant_one_bit_position_inner(nval, sizeof(long));}unsigned most_significant_one_bit_position_longlong(long long val) { unsigned long long nval = (unsigned long long)val; return most_significant_one_bit_position_inner(nval, sizeof(long long));}
NOTE haven't tested (any)!!