46

what I'm after is something I can feed a number into and it will return the highest order bit. I'm sure there's a simple way. Below is an example output (left is the input)

1 -> 1
2 -> 2
3 -> 2
4 -> 4
5 -> 4
6 -> 4
7 -> 4
8 -> 8
9 -> 8
...
63 -> 32
Harley Holcombe
  • 175,848
  • 15
  • 70
  • 63

13 Answers13

93

From Hacker's Delight:

int hibit(unsigned int n) {
    n |= (n >>  1);
    n |= (n >>  2);
    n |= (n >>  4);
    n |= (n >>  8);
    n |= (n >> 16);
    return n - (n >> 1);
}

This version is for 32-bit ints, but the logic can be extended for 64-bits or higher.

erickson
  • 265,237
  • 58
  • 395
  • 493
  • 1
    isn't it supposed to be a bit more efficient to use XOR in the last line? n ^ (n >> 1) – alveko May 28 '13 at 15:48
  • 3
    @alveko while XOR can be implemented faster than subtraction at the transistor/gate level, they will take the same number of clock cycles on most modern CPUs – Drew McGowen Jan 08 '15 at 23:49
  • 3
    less transistors, more efficiency, less heat, more cycles :) – Steazy Feb 16 '16 at 08:42
  • 9
    For intuition, this "spreads" the MSB to the right, so that 0b100010 becomes 0b111111, then shifts right for 0b011111 and subtracts that, yielding 0b100000. – Warty Jun 16 '18 at 10:04
  • Could any one tell me what the theory behind it? – codexplorer Aug 28 '21 at 07:29
  • But this will not work for the case, where all bit of the numbers are set. It incorrectly returns 0. Consider 0x80000000 for a 32 bit number. – Yogesh Kumar Gupta Sep 28 '21 at 13:00
  • @YogeshKumarGupta In that case, wouldn’t it return 0xFFFFFFFF - 0x7FFFFFFF = 0x80000000? Please explain where you see an error. – erickson Sep 28 '21 at 13:18
  • Oh please pardon me, You are right. I was using the parameter n as signed int. In case of unsigned int, Your code works fine. – Yogesh Kumar Gupta Sep 28 '21 at 13:25
  • @YogeshKumarGupta Okay, I see. It's a little unclear how to define "highest order bit" for negative numbers. Would it be the "sign bit", since it will always be set for negative numbers? The highest order bit of the absolute value? This function handles unsigned types, where the meaning is unambiguous. – erickson Sep 28 '21 at 15:44
  • IMO, it should be signed bit for all the negative numbers. – Yogesh Kumar Gupta Sep 29 '21 at 05:05
42

fls bottoms out to a hardware instruction on many architectures. I suspect this is probably the simplest, fastest way of doing it.

1<<(fls(input)-1)
Fabian
  • 6,973
  • 2
  • 26
  • 27
  • 2
    Clearly the best answer. I wonder why all those websites like bit twiddling hacks, who focus so much on reducing the number of operations for this kind of problems, don't even mention this. – Cimbali Mar 04 '14 at 19:07
  • 1
    What happens if a bit is not set? How does one shift left by a negative count? I believe that's undefined behavior. – jww Sep 21 '14 at 00:50
  • 2
    @jww That is correct. `fls(0)` -> 0, leaving the rhs of `<<` negative, which is undefined. In my defense, this was not stated in the problem space ;-) – Fabian Sep 23 '14 at 00:51
  • @Fabian - OK, plus one. – jww Sep 23 '14 at 00:52
  • 1
    This should be the accepted answer. I'm glad I kept scrolling! – krs013 Feb 13 '15 at 19:25
  • 1
    @krs013 - I don't know. It isn't available outside of POSIX if not mistaken. – AturSams Sep 29 '15 at 15:54
  • Is ``fls`` the same as ``ffs``? I test the answer in my environment using ``ffs`` and the result seems not right for case like ``input = 5``. – xxks-kkk Jan 02 '17 at 06:14
  • ffs (find first significant) is the opposite of fls (find last significant) (fls finds most significant bit, ffs finds the least significant bit). – berkus Apr 03 '17 at 18:29
  • `_BitScanReverse()` reportedly the same thing for microsoft, so could be used in place of `fls()` eg, by a conditionalt #define – Jasen Dec 07 '17 at 23:03
  • I don't know why I can't use the `fls()` function. I tried to `#include ` as the manual says but still don't find it... Is it deprecated? I don't know. – Alberto Ursino May 19 '20 at 22:55
  • [`fls` isn't defined by POSIX, though `ffs` is.](https://pubs.opengroup.org/onlinepubs/9699919799/). glibc hasn't got it either. FreeBSD does, but OpenBSD doesn't. – Nate Eldredge Jul 06 '20 at 04:26
34

This should do the trick.

int hob (int num)
{
    if (!num)
        return 0;

    int ret = 1;

    while (num >>= 1)
        ret <<= 1;

    return ret;
}

hob(1234) returns 1024
hob(1024) returns 1024
hob(1023) returns 512

Kyle Cronin
  • 77,653
  • 43
  • 148
  • 164
  • 1
    To make it work with zeros just add: while (num >>= 1 && num) – Paul Hargreaves Sep 10 '08 at 06:21
  • Actually you need an if to check for zero. Since ret starts at 1 and grows, this algorithm won't make it hit 0, the answer for the input of 0. – Kyle Cronin Sep 10 '08 at 14:39
  • 3
    My answer is better. No loops! – erickson Sep 20 '08 at 00:01
  • a good compiler will unroll loops for performance. If it actually does perform faster w/o the loop. – davenpcj Feb 21 '12 at 17:09
  • 4
    For GCC, the better function is __builtin_clz(v) -- it returns the number of leading (binary) zeros, and hence you can get the most significant bit position by 32-clz(num) (or 64-clzll(num) for 64 bit) – Soren Oct 17 '13 at 16:56
27

like obfuscated code? Try this:

1 << ( int) log2( x)

dmityugov
  • 4,390
  • 23
  • 18
  • 1
    I love this solution, but it's just a little too obfuscated. Still gets a vote as the most compact solution. – Harley Holcombe Sep 11 '08 at 00:09
  • 12
    If you want to pawn the job off on the FPU, sure. :) – Jeffrey Hantin Jan 23 '09 at 03:52
  • 11
    Mathematically correct, but this could be much slower than bitwise operations. – mateusza Feb 02 '11 at 12:36
  • But x86 FPUs are plenty fast these days. – Prof. Falken Sep 07 '12 at 09:37
  • 1
    It is possible to find `log2` using bitwise, [see my answer](http://stackoverflow.com/a/12376351/111307) – bobobobo Sep 11 '12 at 19:10
  • 4
    If you cast it to double first, the exponent part of the number readily tells you the order. – Calmarius Sep 20 '13 at 13:35
  • I'm currently looking for a solution to this same problem and this makes my brain hurt. – Joshua Sep 22 '13 at 03:41
  • If you want speed and know what the value would be at compile time, use `boost::static_log2` – Cory-G Jul 31 '14 at 23:34
  • 4
    Be careful with the number representations. This recipe works fine for positive 32 bit integers. But `std::log2()` returns `nan` for negative arguments and `int(nan)` evaluates to `0x80000000` which is the largest negative int. This can be observed for g++7.3 but I am afraid that this is not portable. Next issue is with roundoff-errors. When you feed 64 bit numbers, everything works fine up to 2^{48}-1. But for 2^{49}-1 the recipe returns 2^{49}. – hermannk Jan 25 '18 at 22:07
9

Little bit late to this party but the simplest solution I found, given a modern GCC as a compiler is simply:

static inline int_t get_msb32 (register unsigned int val)
{
  return 32 - __builtin_clz(val);
}

static inline int get_msb64 (register unsigned long long val)
{
  return 64 - __builtin_clzll(val);
}

It's even relatively portable (at the very least it will work on any GCC platform).

Kean
  • 592
  • 5
  • 10
7

Continually remove the low order bit comes to mind...

int highest_order_bit( int x )
{
    int y = x;
    do { 
        x = y;
        y = x & (x-1); //remove low order bit
    }
    while( y != 0 );
    return x;
}
Kyle Cronin
  • 77,653
  • 43
  • 148
  • 164
nlucaroni
  • 47,556
  • 6
  • 64
  • 86
5

The linux kernel has a number of handy bitops like this, coded in the most efficient way for a number of architectures. You can find generic versions in include/asm-generic/bitops/fls.h (and friends), but see also include/asm-x86/bitops.h for a definition using inline assembly if speed is of the essence, and portability is not.

Adam Tyszecki
  • 49
  • 1
  • 5
theorbtwo
  • 561
  • 3
  • 5
  • 1
    The Linux kernel is full of undefined behavior in bitops. I don't recommend anyone use it (or copy/paste the routines) unless they know what they are doing or have a complete set of self tests for the functionality. – jww Sep 21 '14 at 00:46
4

This can easily be solved with existing library calls.

int highestBit(int v){
  return fls(v) << 1;
}

The Linux man page gives more details on this function and its counterparts for other input types.

jww
  • 97,681
  • 90
  • 411
  • 885
dharga
  • 2,187
  • 3
  • 24
  • 33
4

A fast way to do this is via a look-up table. For a 32-bit input, and an 8-bit look-up table, in only requires 4 iterations:

int highest_order_bit(int x)
{
    static const int msb_lut[256] =
        {
            0, 0, 1, 1, 2, 2, 2, 2, // 0000_0000 - 0000_0111
            3, 3, 3, 3, 3, 3, 3, 3, // 0000_1000 - 0000_1111
            4, 4, 4, 4, 4, 4, 4, 4, // 0001_0000 - 0001_0111
            4, 4, 4, 4, 4, 4, 4, 4, // 0001_1000 - 0001_1111
            5, 5, 5, 5, 5, 5, 5, 5, // 0010_0000 - 0010_0111
            5, 5, 5, 5, 5, 5, 5, 5, // 0010_1000 - 0010_1111
            5, 5, 5, 5, 5, 5, 5, 5, // 0011_0000 - 0011_0111
            5, 5, 5, 5, 5, 5, 5, 5, // 0011_1000 - 0011_1111

            6, 6, 6, 6, 6, 6, 6, 6, // 0100_0000 - 0100_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0100_1000 - 0100_1111
            6, 6, 6, 6, 6, 6, 6, 6, // 0101_0000 - 0101_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0101_1000 - 0101_1111
            6, 6, 6, 6, 6, 6, 6, 6, // 0110_0000 - 0110_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0110_1000 - 0110_1111
            6, 6, 6, 6, 6, 6, 6, 6, // 0111_0000 - 0111_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0111_1000 - 0111_1111

            7, 7, 7, 7, 7, 7, 7, 7, // 1000_0000 - 1000_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1000_1000 - 1000_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1001_0000 - 1001_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1001_1000 - 1001_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1010_0000 - 1010_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1010_1000 - 1010_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1011_0000 - 1011_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1011_1000 - 1011_1111

            7, 7, 7, 7, 7, 7, 7, 7, // 1100_0000 - 1100_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1100_1000 - 1100_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1101_0000 - 1101_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1101_1000 - 1101_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1110_0000 - 1110_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1110_1000 - 1110_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1111_0000 - 1111_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1111_1000 - 1111_1111
        };

    int byte;
    int byte_cnt;

    for (byte_cnt = 3; byte_cnt >= 0; byte_cnt--)
    {
        byte = (x >> (byte_cnt * 8)) & 0xff;
        if (byte != 0)
        {
            return msb_lut[byte] + (byte_cnt * 8);
        }
    }

    return -1;
}
Ben Lever
  • 2,023
  • 7
  • 26
  • 34
3

If you do not need a portable solution and your code is executing on an x86 compatible CPU you can use _BitScanReverse() intrinsic function provided by Microsoft Visual C/C++ compiler. It maps to BSR CPU instruction which returns the highest bit set.

Igor Levicki
  • 1,017
  • 10
  • 17
3

The best algorithm I like very much is:

unsigned hibit(unsigned n) {
    n |= (n >>  1u);
    n |= (n >>  2u);
    n |= (n >>  4u);
    n |= (n >>  8u);
    n |= (n >> 16u);
    return n - (n >> 1);
}

And it's easily extended for uint64_t like that:

uint64_t hibit(uint64_t n) {
    n |= (n >>  1u);
    n |= (n >>  2u);
    n |= (n >>  4u);
    n |= (n >>  8u);
    n |= (n >> 16u);
    n |= (n >> 32u);
    return n - (n >> 1);
}

or even to __int128

__int128 hibit(__int128 n) {
    n |= (n >>  1u);
    n |= (n >>  2u);
    n |= (n >>  4u);
    n |= (n >>  8u);
    n |= (n >> 16u);
    n |= (n >> 32u);
    n |= (n >> 64u);
    return n - (n >> 1);
}

In addition is crossplatphorm solution independend of using compilator

2
// Note doesn't cover the case of 0 (0 returns 1)
inline unsigned int hibit( unsigned int x )
{
  unsigned int log2Val = 0 ;
  while( x>>=1 ) log2Val++;  // eg x=63 (111111), log2Val=5
  return 1 << log2Val ; // finds 2^5=32
}
bobobobo
  • 64,917
  • 62
  • 258
  • 363
0

A nifty solution I came up with is to binary search the bits.

uint64_t highestBit(uint64_t a, uint64_t bit_min, uint64_t bit_max, uint16_t bit_shift){
    if(a == 0) return 0;
    if(bit_min >= bit_max){
        if((a & bit_min) != 0)
            return bit_min;
        return 0;
    }
    uint64_t bit_mid = bit_max >> bit_shift;
    bit_shift >>= 1;
    if((a >= bit_mid) && (a < (bit_mid << 1)))
        return bit_mid;
    else if(a > bit_mid)
        return highestBit(a, bit_mid, bit_max, bit_shift);
    else
        return highestBit(a, bit_min, bit_mid, bit_shift);

}

Bit max is the highest power of 2, so for a 64 bit number it would be 2^63. Bit shift should be initialized to half the number of bits, so for 64 bits, it would be 32.

Gavin Sellers
  • 654
  • 1
  • 15
  • 27