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

后端 未结 27 2770
终归单人心
终归单人心 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:18

    Here are some (simple) benchmarks, of algorithms currently given on this page...

    The algorithms have not been tested over all inputs of unsigned int; so check that first, before blindly using something ;)

    On my machine clz (__builtin_clz) and asm work best. asm seems even faster then clz... but it might be due to the simple benchmark...

    //////// go.c ///////////////////////////////
    // compile with:  gcc go.c -o go -lm
    #include 
    #include 
    #include 
    #include 
    
    /***************** math ********************/
    
    #define POS_OF_HIGHESTBITmath(a) /* 0th position is the Least-Signif-Bit */    \
      ((unsigned) log2(a))         /* thus: do not use if a <= 0 */  
    
    #define NUM_OF_HIGHESTBITmath(a) ((a)               \
                      ? (1U << POS_OF_HIGHESTBITmath(a))    \
                      : 0)
    
    
    
    /***************** clz ********************/
    
    unsigned NUM_BITS_U = ((sizeof(unsigned) << 3) - 1);
    #define POS_OF_HIGHESTBITclz(a) (NUM_BITS_U - __builtin_clz(a)) /* only works for a != 0 */
    
    #define NUM_OF_HIGHESTBITclz(a) ((a)                    \
                     ? (1U << POS_OF_HIGHESTBITclz(a))  \
                     : 0)
    
    
    /***************** i2f ********************/
    
    double FF;
    #define POS_OF_HIGHESTBITi2f(a) (FF = (double)(ui|1), ((*(1+(unsigned*)&FF))>>20)-1023)
    
    
    #define NUM_OF_HIGHESTBITi2f(a) ((a)                    \
                     ? (1U << POS_OF_HIGHESTBITi2f(a))  \
                     : 0)
    
    
    
    
    /***************** asm ********************/
    
    unsigned OUT;
    #define POS_OF_HIGHESTBITasm(a) (({asm("bsrl %1,%0" : "=r"(OUT) : "r"(a));}), OUT)
    
    #define NUM_OF_HIGHESTBITasm(a) ((a)                    \
                     ? (1U << POS_OF_HIGHESTBITasm(a))  \
                     : 0)
    
    
    
    
    /***************** bitshift1 ********************/
    
    #define NUM_OF_HIGHESTBITbitshift1(a) (({   \
      OUT = a;                  \
      OUT |= (OUT >> 1);                \
      OUT |= (OUT >> 2);                \
      OUT |= (OUT >> 4);                \
      OUT |= (OUT >> 8);                \
      OUT |= (OUT >> 16);               \
          }), (OUT & ~(OUT >> 1)))          \
    
    
    
    /***************** bitshift2 ********************/
    int POS[32] = {0, 1, 28, 2, 29, 14, 24, 3,
                 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19,
                 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
    
    #define POS_OF_HIGHESTBITbitshift2(a) (({   \
      OUT = a;                  \
      OUT |= OUT >> 1;              \
      OUT |= OUT >> 2;              \
      OUT |= OUT >> 4;              \
      OUT |= OUT >> 8;              \
      OUT |= OUT >> 16;             \
      OUT = (OUT >> 1) + 1;             \
          }), POS[(OUT * 0x077CB531UL) >> 27])
    
    #define NUM_OF_HIGHESTBITbitshift2(a) ((a)              \
                           ? (1U << POS_OF_HIGHESTBITbitshift2(a)) \
                           : 0)
    
    
    
    #define LOOPS 100000000U
    
    int main()
    {
      time_t start, end;
      unsigned ui;
      unsigned n;
    
      /********* Checking the first few unsigned values (you'll need to check all if you want to use an algorithm here) **************/
      printf("math\n");
      for (ui = 0U; ui < 18; ++ui)
        printf("%i\t%i\n", ui, NUM_OF_HIGHESTBITmath(ui));
    
      printf("\n\n");
    
      printf("clz\n");
      for (ui = 0U; ui < 18U; ++ui)
        printf("%i\t%i\n", ui, NUM_OF_HIGHESTBITclz(ui));
    
      printf("\n\n");
    
      printf("i2f\n");
      for (ui = 0U; ui < 18U; ++ui)
        printf("%i\t%i\n", ui, NUM_OF_HIGHESTBITi2f(ui));
    
      printf("\n\n");
    
      printf("asm\n");
      for (ui = 0U; ui < 18U; ++ui) {
        printf("%i\t%i\n", ui, NUM_OF_HIGHESTBITasm(ui));
      }
    
      printf("\n\n");
    
      printf("bitshift1\n");
      for (ui = 0U; ui < 18U; ++ui) {
        printf("%i\t%i\n", ui, NUM_OF_HIGHESTBITbitshift1(ui));
      }
    
      printf("\n\n");
    
      printf("bitshift2\n");
      for (ui = 0U; ui < 18U; ++ui) {
        printf("%i\t%i\n", ui, NUM_OF_HIGHESTBITbitshift2(ui));
      }
    
      printf("\n\nPlease wait...\n\n");
    
    
      /************************* Simple clock() benchmark ******************/
      start = clock();
      for (ui = 0; ui < LOOPS; ++ui)
        n = NUM_OF_HIGHESTBITmath(ui);
      end = clock();
      printf("math:\t%e\n", (double)(end-start)/CLOCKS_PER_SEC);
    
      start = clock();
      for (ui = 0; ui < LOOPS; ++ui)
        n = NUM_OF_HIGHESTBITclz(ui);
      end = clock();
      printf("clz:\t%e\n", (double)(end-start)/CLOCKS_PER_SEC);
    
      start = clock();
      for (ui = 0; ui < LOOPS; ++ui)
        n = NUM_OF_HIGHESTBITi2f(ui);
      end = clock();
      printf("i2f:\t%e\n", (double)(end-start)/CLOCKS_PER_SEC);
    
      start = clock();
      for (ui = 0; ui < LOOPS; ++ui)
        n = NUM_OF_HIGHESTBITasm(ui);
      end = clock();
      printf("asm:\t%e\n", (double)(end-start)/CLOCKS_PER_SEC);
    
      start = clock();
      for (ui = 0; ui < LOOPS; ++ui)
        n = NUM_OF_HIGHESTBITbitshift1(ui);
      end = clock();
      printf("bitshift1:\t%e\n", (double)(end-start)/CLOCKS_PER_SEC);
    
      start = clock();
      for (ui = 0; ui < LOOPS; ++ui)
        n = NUM_OF_HIGHESTBITbitshift2(ui);
      end = clock();
      printf("bitshift2\t%e\n", (double)(end-start)/CLOCKS_PER_SEC);
    
      printf("\nThe lower, the better. Take note that a negative exponent is good! ;)\n");
    
      return EXIT_SUCCESS;
    }
    

提交回复
热议问题