Sometimes in-place operations are used. You need to quickly find the position (subscript) of the first 1 or 0 of an integer binary )? For example, if the binary value of decimal number 100 is 1100100, its first 1 is at the position (bsf, bit scan forward) or 6 (bsr, bit scan in reverse order), because it is only used to store one state, it does not matter whether bsf or bsr is used.
The first idea to solve this problem is to use the inline assembly method and use special CPU commands for searching. However, the Assembly is less portable, and different CPU models may use different commands, the execution speed is also different.
Suppose we want to find the first 1 of a 64-bit unsigned integer binary. We can use bsf, AT & T assembly (gcc Assembly) to do this:
1 // bit scan forward for 64 bit integral number
2/* ============================================== ======= */
3 inline int bsf_asm (uint64_t w)
4 {
5 int x1, x2;
6 asm ("bsf % 0, % 0 \ n" "jnz 1f \ n" "bsf % 1, % 0 \ n" "jz 1f \ n" "addl $32, % 0 \ n"
7 "1:": "= & q" (x1), "= & q" (x2): "1" (int) (w> 32 )),
8 "0" (int) w ));
9 return x1;
10}
If we use C for implementation, it will be a little troublesome. Here we will not talk about complicated mathematical principles, just code.
1 // bit scan forward for 64 bit integral number
2/* ============================================== ======= */
3 inline int bsf_folded (uint64_t bb)
4 {
5 static const int lsb_64_table [64] =
6 {
7 63, 30, 3, 32, 59, 14, 11, 33,
8 60, 24, 50, 9, 55, 19, 21, 34,
9 61, 29, 2, 53, 51, 23, 41, 18,
10 56, 28, 1, 43, 46, 27, 0, 35,
11 62, 31, 58, 4, 5, 49, 54, 6,
12 15, 52, 12, 40, 7, 42, 45, 16,
13 25, 57, 48, 13, 10, 39, 8, 44,
14 20, 47, 38, 22, 17, 37, 36, 26
15 };
16 unsigned int folded;
17 bb ^ = bb-1;
18 folded = (int) bb ^ (bb> 32 );
19 return lsb_64_table [folded * 0x78291ACF> 26];
20}
If you want to search for the subscript of the first 1 in the binary of an integer from the back to the front, you can use assembly to do this.
1 // bit scan in reverse order for 64 bit integral number
2/* ============================================== ======= */
3 inline int bsr_asm (uint64_t w)
4 {
5 int x1, x2;
6 asm ("bsr % 1, % 0 \ n" "jnz 1f \ n" "bsr % 0, % 0 \ n" "subl $32, % 0 \ n"
7 "1: addl $32, % 0 \ n": "= & q" (x1), "= & q" (x2): "1" (int) (w> 32 )),
8 "0" (int) w ));
9 return x1;
10}
If C is used for implementation, it is also relatively simple. The principle of divide and conquer is not too slow.
1 // a logn (n = 32) algorithm for bit scan in reverse order
2/* ============================================== ======= */
3 inline int bsr32 (uint32_t bb)
4 {
5 static const char msb_256_table [1, 256] =
6 {
7 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
8 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
9 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
10 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
11 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
12 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
13 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
14 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
15 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
16 };
17 int result = 0;
18
19 if (bb> 0 xFFFF)
20 {
21 bb> = 16;
22 result + = 16;
23}
24 if (bb> 0xFF)
25 {
26 bb> = 8;
27 result + = 8;
28}
29
30 return (result + msb_256_table [bb]);
31}
32
33/* ============================================ ======= */
34 inline int bsr_in_C (uint64_t bb)
35 {
36 const uint32_t hb = bb> 32;
37 return hb? 32 + bsr32 (uint32_t) hb): bsr32 (uint32_t) bb );
38
39}
40
The following seems to be okay. If it fails,-1023 is returned. The speed depends on the compiler's preferences.
1 // bit scan in reverse order for 64 bit integral number
2/* ============================================== ======= */
3 inline int bsr_double (uint64_t bb)
4 {
5 union
6 {
7 double d;
8 struct
9 {
10 unsigned int mantissal: 32;
11 unsigned int mantissia: 20;
12 unsigned int exponent: 11;
13 unsigned int sign: 1;
14 };
15} ud;
16 ud. d = (double) (bb &~ (Bb> 32 ));
Return ud. exponent-1023;
18}
19
The preceding uint64_t and uint32_t are integer types supported by the new C ++ standard, which are equivalent to the old unsigned long and unsigned long types respectively. The above code is not my original one, but a friend from abroad. I posted it here after a bit of processing. The copyright belongs to the original author. If I remember correctly, it should be GNU.