To understand the difference between the `>>`

and `>>>`

signed/unsigned right shift operators, I couldn't dodge the need to look into how computers store negative numbers.

If we didn't need to represent negative numbers, then n bits could store 2**n numbers. 8 bits, for instance, could simply store any number between 0 and 255.

But if we do need to make sure that any given absolute value needs to be either positive or negative, we must assign a bit to represent that. Our bits to the right are already busy representing numeric values, so let's say the leftmost bit is our sign, 1 for negative, 0 for positive. This will obviously cut down the maximum absolute value we can represent by half.

Naively we might assume that the ones and zeroes to the right of our sign bit would remain the same. If 0001 is 1, then 1001 would be -1, right? Sadly this turns out not to be very practical. If we add 0001 to 1001, do we get... 1010, -2? And perhaps even more confusingly, what is 1000? -0?

It turns out there's a neat solution though. First we find the 'one's complement' of our binary number by inverting all its bits. In the case of our 0001, that would be 1110. Then we add 1 to find the two's complement, in this case 1111. 1111 + 0001 == (1)0000 == 0. And we can also see that -0 is the inverse of 0000 (== 1111) + 1 = 0000. Much better behavior!

When we use a signed right shift operator, we make sure to carry the bit that represents the sign, and prepend it to our result, maintaining the intended sense of our numeric value in way that simply shifting the bits unceremoniously rightward would not.

Why would a language even need an unsigned right shift operator? It turns out that there are some interesting applications. But they are probably beyond the scope of this particular rabbit hole. For now!