Quantcast
Channel: What is the fastest/most efficient way to find the highest set bit (msb) in an integer in C? - Stack Overflow
Viewing all articles
Browse latest Browse all 36

Answer by ceorron for What is the fastest/most efficient way to find the highest set bit (msb) in an integer in C?

$
0
0

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)!!


Viewing all articles
Browse latest Browse all 36

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>