简体   繁体   中英

Reverse bits of a 32 bit unsigned integer

The problem is to reverse the bits of a 32 bit unsigned integer (since Java doesn't have unsigned integers we use long).

Here are two versions of my code. I have two concerns:

(1) why my 1st and 2nd solution don't return the same value (correct or not)

(2) where my 1st and 2nd solution went wrong in not getting the correct answer

    //reverse(3) returns 0
    public static long reverse(long a) {
        long numBits = 32;
        long finalResult = 0;
        for(int i = 0; i < numBits; i++){
            long ithBit = a & (1 << i);
            finalResult = finalResult + ithBit * (1 << (numBits - i - 1));
        }
        return finalResult;
    }

Second version:

    //reverse(3) return 4294967296
    public static long reverse(long a) {
        long numBits = 32L;
        long finalResult = 0L;
        for(long i = 0L; i < numBits; i++){
            long ithBit = a & (1L << i);
            finalResult = finalResult + ithBit * (1L << (numBits - i - 1L));
        }
        return finalResult;
    }

This code (the solution) returns the correct answer, however:

    //reverse(3) returns 3221225472
    public static long reverse(long A) {
        long rev = 0;

        for (int i = 0; i < 32; i++) {
            rev <<= 1;
            if ((A & (1 << i)) != 0)
                rev |= 1;
        }

        return rev;

    }

Thanks!

since Java doesn't have unsigned integers we use long.

That's generally unecessary since all arithmetic operations except division and comparison result in identical bit patterns for unsigned and signed numbers in two's complement representation , which java uses. And for the latter two ops Integer.divideUnsigned(int, int) and Integer.compareUnsigned(int, int) are available.

The problem is to reverse the bits of a 32 bit unsigned integer

There's Integer.reverse(int)

Relevant docs , spending some time reading them is highly recommended.

In both versions you have a logic problem here:

ithBit * (1 << (numBits - i - 1));

because the two numbers multiply to the same bit pattern of bit 31 (the 32nd) being set.

In version 1, the amount added is -2^31 if bit 0 is set because you're bit-shifting an int so the bit-shifted result is int which represents -2^31 as the high bit being set, or 2^31 for every other bit, which is possible due to the auto-cast to long of the result. You have two of each kind of bit ( 0 and non 0 ) so the result is zero.

Version 2 has the same problem, but without the negative int issue because you're bit shifting a long . Each bit that is 1 will add 2^31 . The number 3 has 2 bits set, so your result is 2 * 2^31 (or 2^32 ) which is 4294967296 .


To fix your logic, use version 2 but remove the multiply by ithBit .

Let's have a look at your values as you iterate. For clarification, we'll have a look at the intermediate values, so we'll change code to:

int n = (1 << (numBits - i - 1));
long m = ithBit * n;
finalResult = finalResult + m;

Your starting value is 3:

a = 0000 0000 0000 0000 0000 0000 0000 0011

First loop iteration (i = 0):

ithBit      = 00000000 00000000 00000000 00000001
n           = 11111111 11111111 11111111 11111111 10000000 00000000 00000000 00000000
m           = 11111111 11111111 11111111 11111111 10000000 00000000 00000000 00000000
finalResult = 11111111 11111111 11111111 11111111 10000000 00000000 00000000 00000000

Second loop iteration (i = 1):

ithBit      = 00000000 00000000 00000000 00000010
n           = 01000000 00000000 00000000 00000000
m           = 10000000 00000000 00000000 00000000
finalResult = 00000000 00000000 00000000 00000000

As you can see, the first iterate sets n = 1 << 31 , which is -2147483648. In your second version you do n = 1L << 31 , which is 2147483648, and that's why your two versions give different results.

As you can also see, you definitely don't want to do the m = ithBit * n part.

Have a look at your number by printing them yourself, and you'll figure it out.

BTW, here's my version. If you have trouble understanding it, try printing the intermediate values to see what's going on.

public static long reverse4(long a) {
    long rev = 0;
    for (int i = 0; i < 32; i++, a >>= 1)
        rev = (rev << 1) | (a & 1);
    return rev;
}

Problem with your both examples is that the "i-th bit" isn't a 0 or 1 but rather masked off. In either case, the 31'th bit is 0x8000_0000. In the first case, this is an int, so it is negative, and when converted to a long it stays negative. In the second case it is already a long, so it stays positive. To fix it so it does what you intended, do:

 ithBit = (a >>> i) & 1;

By the way, using long is silly; unsigned vs. signed makes no difference as long as you understand that there are two types of shifts in Java.

By the way, all three examples are terrible. If you are doing bit manipulation, you want speed, right? (Why else bother with bits?)

This is how to do it right (not mine, stolen from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits ):

a = ((a >>> 1) & 0x55555555) | ((a & 0x55555555) << 1);
a = ((a >>> 2) & 0x33333333) | ((a & 0x33333333) << 2);
a = ((a >>> 4) & 0x0F0F0F0F) | ((a & 0x0F0F0F0F) << 4);
a = ((a >>> 8) & 0x00FF00FF) | ((a & 0x00FF00FF) << 8);
a = ( a >>> 16             ) | ( a               << 16);

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