简体   繁体   中英

Understanding the given snippet on bit reversal

I found this snippet on 'codefights' submitted by a programmer. My solution to the problem was 30 lines, whereas this is just a beauty. But I am not able to understand the logic. Can anyone explain this.

int mirrorBits(int a) {
 int r = 0;

 for (; a; a >>= 1) 
    r = r << 1 | a & 1;  
 return r;
}

input a = 8; output : 1

First of all, there is a very good StackOverflow answer here: Most Efficient Algorithm for Bit Reversal ( from MSB->LSB to LSB->MSB) in C

The algorithm makes use of

>> ... binary shift right (100b >> 1 == 10b)
<< ... binary shift left (100b << 1 == 1000b
| .... binary or (100b | 10b == 110b)
& .... binary and (111b & 100b == 100b)

The for loop shifts a to the right until all bits have fallen out of a.

Imagine you start with a = 101101 then a >>= 1 does the following:

At the end of loop 1:  a == 10110
At the end of loop 2:  a == 01011
At the end of loop 3:  a == 00101
At the end of loop 4:  a == 00010
At the end of loop 5:  a == 00001
At the end of loop 6:  a == 00000 (condition fails -> loop ends)

The body of the loop shifts b one bit right, uses & to mask the last bit of a and adds it as last digit to b. The or can be used to add the last digit because << inserts 0 for all "new" bits.

Imagine you start with a = 101101

  • loop 1: a = 10110 1 , r = 0 => 0 1
  • loop 2: a = 01011 0 , r = 01 => 01 0
  • loop 3: a = 00101 1 , r = 010 => 010 1
  • loop 4: a = 00010 1 , r = 0101 => 0101 1
  • loop 5: a = 00001 0 , r = 01011 => 01011 0
  • loop 6: a = 00000 1 , r = 010110 => 010110 1

In detail the inner loop #3 does the following: (a is 001011 and r is 010)

r << 1 changes r from 010 to 0100. The last digit is the inserted 0. a & 1 masks the current last bit from a (the 1 in 00101 1 ) now we have (0100 | 1) which has the result 0101.

Warning : This algorithm is not really mirroring the bits, because you do not get the original value if you apply the algorithm to the result.

If you need a mirrored 32-bit unsigned integer you have to loop 32 times independently of the value of a:

unsigned int r = 0;
unsigned int a = 12345;

for(int i = 0; i < 32; ++i)
{
   r = (r << 1) | (a & 1);
   a >>= 1;
}

If you apply this algorithm twice, you should get the original value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM