Why if (n & -n) == n then n is a power of 2?

Line 294 of java.util.Random source says

if ((n & -n) == n) // i.e., n is a power of 2
    // rest of the code

Why is this?


Because in 2's complement, -n is ~n+1.

If n is a power of 2, then it only has one bit set. So ~n has all the bits set except that one. Add 1, and you set the special bit again, ensuring that n & (that thing) is equal to n.

The converse is also true because 0 and negative numbers were ruled out by the previous line in that Java source. If n has more than one bit set, then one of those is the highest such bit. This bit will not be set by the +1 because there's a lower clear bit to "absorb" it:

 n: 00001001000
~n: 11110110111
-n: 11110111000  // the first 0 bit "absorbed" the +1
        ^
        |
        (n & -n) fails to equal n at this bit.

The description is not entirely accurate because (0 & -0) == 0 but 0 is not a power of two. A better way to say it is

((n & -n) == n) when n is a power of two, or the negative of a power of two, or zero.

If n is a power of two, then n in binary is a single 1 followed by zeros. -n in two's complement is the inverse + 1 so the bits lines up thus

 n      0000100...000
-n      1111100...000
 n & -n 0000100...000

To see why this work, consider two's complement as inverse + 1, -n == ~n + 1

n          0000100...000
inverse n  1111011...111
                     + 1
two's comp 1111100...000

since you carry the one all the way through when adding one to get the two's complement.

If n were anything other than a power of two† then the result would be missing a bit because the two's complement would not have the highest bit set due to that carry.

† - or zero or a negative of a power of two ... as explained at the top.