I understand the >>> fixes the overflow: when adding two big positive longs you may end up with a negative number. Can someone explain how this bitwise shift magically fixes the overflow problem? And how it is different from >> ?
My suspicion: I think it has to do with the fact that Java uses two’s-complement so the overflow is the right number if we had the extra space but because we don’t it becomes negative. So when you shift and pad with zero it magically gets fixed due to the two’s-complement. But I can be wrong and someone with a bitwise brain has to confirm. 🙂
In short,
(high + low) >>> 1is a trick that uses the unused sign-bit to perform a correct average of non-negative numbers.Under the assumption that
highandloware both non-negative, we know for sure that the upper-most bit (the sign-bit) is zero.So both
highandloware in fact 31-bit integers.When you add them together they may “spill” over into the top-bit.
As a signed 32-bit integer, it is overflow and flips negative. Therefore
(high + low) / 2is wrong becausehigh + lowcould be negative.As unsigned 32-bit integers, the sum is correct. All that’s needed is to divide it by 2.
Of course Java doesn’t support unsigned integers, so the best thing we have to divide by 2 (as an unsigned integer) is the logical right-shift
>>>.In languages with unsigned integers (such as C and C++), it gets trickier since your input can be full 32-bit integers. One solution is:
low + ((high - low) / 2)Finally to enumerate the differences between
>>>,>>, and/:>>>is logical right-shift. It fills the upper bits with zero.>>is arithmetic right-shift. It fills the upper its with copies of the original top bit./is division.Mathematically:
x >>> 1treatsxas an unsigned integer and divides it by two. It rounds down.x >> 1treatsxas a signed integer and divides it by two. It rounds towards negative infinity.x / 2treatsxas a signed integer and divides it by two. It rounds towards zero.