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

后端 未结 27 2692
终归单人心
终归单人心 2020-11-22 03:35

If I have some integer n, and I want to know the position of the most significant bit (that is, if the least significant bit is on the right, I want to know the position of

相关标签:
27条回答
  • 2020-11-22 04:01

    As the answers above point out, there are a number of ways to determine the most significant bit. However, as was also pointed out, the methods are likely to be unique to either 32bit or 64bit registers. The stanford.edu bithacks page provides solutions that work for both 32bit and 64bit computing. With a little work, they can be combined to provide a solid cross-architecture approach to obtaining the MSB. The solution I arrived at that compiled/worked across 64 & 32 bit computers was:

    #if defined(__LP64__) || defined(_LP64)
    # define BUILD_64   1
    #endif
    
    #include <stdio.h>
    #include <stdint.h>  /* for uint32_t */
    
    /* CHAR_BIT  (or include limits.h) */
    #ifndef CHAR_BIT
    #define CHAR_BIT  8
    #endif  /* CHAR_BIT */
    
    /* 
     * Find the log base 2 of an integer with the MSB N set in O(N)
     * operations. (on 64bit & 32bit architectures)
     */
    int
    getmsb (uint32_t word)
    {
        int r = 0;
        if (word < 1)
            return 0;
    #ifdef BUILD_64
        union { uint32_t u[2]; double d; } t;  // temp
        t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] = 0x43300000;
        t.u[__FLOAT_WORD_ORDER!=LITTLE_ENDIAN] = word;
        t.d -= 4503599627370496.0;
        r = (t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] >> 20) - 0x3FF;
    #else
        while (word >>= 1)
        {
            r++;
        }
    #endif  /* BUILD_64 */
        return r;
    }
    
    0 讨论(0)
  • 2020-11-22 04:02

    What about

    int highest_bit(unsigned int a) {
        int count;
        std::frexp(a, &count);
        return count - 1;
    }
    

    ?

    0 讨论(0)
  • 2020-11-22 04:03

    Although I would probably only use this method if I absolutely required the best possible performance (e.g. for writing some sort of board game AI involving bitboards), the most efficient solution is to use inline ASM. See the Optimisations section of this blog post for code with an explanation.

    [...], the bsrl assembly instruction computes the position of the most significant bit. Thus, we could use this asm statement:

    asm ("bsrl %1, %0" 
         : "=r" (position) 
         : "r" (number));
    
    0 讨论(0)
  • 2020-11-22 04:05

    Woaw, that was many answers. I am not sorry for answering on an old question.

    int result = 0;//could be a char or int8_t instead
    if(value){//this assumes the value is 64bit
        if(0xFFFFFFFF00000000&value){  value>>=(1<<5); result|=(1<<5);  }//if it is 32bit then remove this line
        if(0x00000000FFFF0000&value){  value>>=(1<<4); result|=(1<<4);  }//and remove the 32msb
        if(0x000000000000FF00&value){  value>>=(1<<3); result|=(1<<3);  }
        if(0x00000000000000F0&value){  value>>=(1<<2); result|=(1<<2);  }
        if(0x000000000000000C&value){  value>>=(1<<1); result|=(1<<1);  }
        if(0x0000000000000002&value){  result|=(1<<0);  }
    }else{
      result=-1;
    }
    

    This answer is pretty similar to another answer... oh well.

    0 讨论(0)
  • 2020-11-22 04:05

    My humble method is very simple:

    MSB(x) = INT[Log(x) / Log(2)]

    Translation: The MSB of x is the integer value of (Log of Base x divided by the Log of Base 2).

    This can easily and quickly be adapted to any programming language. Try it on your calculator to see for yourself that it works.

    0 讨论(0)
  • 2020-11-22 04:05

    Here is a fast solution for C that works in GCC and Clang; ready to be copied and pasted.

    #include <limits.h>
    
    unsigned int fls(const unsigned int value)
    {
        return (unsigned int)1 << ((sizeof(unsigned int) * CHAR_BIT) - __builtin_clz(value) - 1);
    }
    
    unsigned long flsl(const unsigned long value)
    {
        return (unsigned long)1 << ((sizeof(unsigned long) * CHAR_BIT) - __builtin_clzl(value) - 1);
    }
    
    unsigned long long flsll(const unsigned long long value)
    {
        return (unsigned long long)1 << ((sizeof(unsigned long long) * CHAR_BIT) - __builtin_clzll(value) - 1);
    }
    

    And a little improved version for C++.

    #include <climits>
    
    constexpr unsigned int fls(const unsigned int value)
    {
        return (unsigned int)1 << ((sizeof(unsigned int) * CHAR_BIT) - __builtin_clz(value) - 1);
    }
    
    constexpr unsigned long fls(const unsigned long value)
    {
        return (unsigned long)1 << ((sizeof(unsigned long) * CHAR_BIT) - __builtin_clzl(value) - 1);
    }
    
    constexpr unsigned long long fls(const unsigned long long value)
    {
        return (unsigned long long)1 << ((sizeof(unsigned long long) * CHAR_BIT) - __builtin_clzll(value) - 1);
    }
    

    The code assumes that value won't be 0. If you want to allow 0, you need to modify it.

    0 讨论(0)
提交回复
热议问题