简体   繁体   中英

Does anyone know why my java code doesn't work properly using n=n/2 while n>>1 does?

This is a problem from leetcode( https://leetcode.com/problems/number-of-1-bits/ ). This method is for counting the 1s this number has in binary. I try to use n=n/2 which doesn't pass every case while n=n>>1 does. Does anyone know why??

public class Numberof1Bits {

public static void main(String[] args) {
    System.out.println(new Numberof1Bits()
            .hammingWeight(0b11111111111111111111111111111111));
}

public int hammingWeight(int n) {
    int count = 0;
    if (n < 0)
        count++;
    for (int i = 0; i < 31; i++) {
        if ((n & 1) == 1)
            count++;
        n = n >> 1;// while this doesn't work when n=n/2;
    }
    return count;
}
}

>> 1 divides an int by two, but the rounding is done using floor, ie rounding towards negative infinity. The relevant quote from the Java Language Specification:

The value of n >> s is n right-shifted s bit positions with sign-extension. The resulting value is floor(n / 2^s).

For example,

 20 >> 1 == 10
 15 >> 1 == 7   (7.5 is rounded down to 7)
-20 >> 1 == -10
-15 >> 1 == -8  (-7.5 is rounded down to -8) 

On the other hand, for / the rounding is done towards zero. This is from the Java Language Specification:

The binary / operator performs division, producing the quotient of its operands. The left-hand operand is the dividend and the right-hand operand is the divisor.

Integer division rounds toward 0.

For example,

 20 / 2 == 10
 15 / 2 == 7    (7.5 is rounded down to 7)
-20 / 2 == -10
-15 / 2 == -7   (-7.5 is rounded UP to -7)

For negative odd integers n , n /= 2 is therefore the same as n >>= 1; n++; n >>= 1; n++; . The n++ will completely change the calculation for the number of set bits.

You're using unsigned ints. 0xFFFFFFFF = -1. -1 >> 1 = -1. -1/2 = 0. It will fail for any number with the most significant bit set.

If Java, the >> operator does a sign-extended bitwise right shift. For example (I use 8 bits digits for clarity's sake):

0b10111111 >> 1 => 0b11011111

The same in decimal:

-65 >> 1 => -33

Bits are shifted right by one position, and the most significant bit is kept as is. My example number (0b10111111) is -65 in decimal. If you divide it by two, you get -32. Yes, we've lost one bit in translation. /2 performs an arithmetic division, which is equivalent to >> 1 only for positive numbers.

In languages that support unsigned ints and an unsigned right shift, n/2 should work as intended.

In java, since >> is signed, you could use >>> which does a right shift without sign extension, and the possibly faster loop:

public int hammingWeight(int n) {
    int count = 0;
    while(n != 0) {
        if ((n & 1) != 0) {
            count++;
        }
        n = n >>> 1;
    }
    return count;
}

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