2

I want to understand the semantics of rights bit shifts x>>k in two's complement properly, in particular why do right bit shifts of size $k$ approximately divide $x$ by $2^k$ (and ideally making this "approx" precise and also handling the arithmetic left bit shift too).

So the representation of a number in two complement is for a $N$ bit length word: $$ x = -a_{N-1} 2^{N-1} + \sum^{N-2}_{i=0} a_{i} 2^i = neg + pos $$ e.g., as a intentionally selected running example $-6$ is $1010_2$ which is $-8 + 0 + 2 + 0$. I'm thinking of bit slots [-8, 4, 2, 1] <-> [-2^3, 2^2, 2^1, 2^0] for each bit. When doing an arithmetic right bit shift we get $1101_2$ which ends up being $-3 = -8 + 4 + 0 + 1$ in twos complement.

When the most significant bit (MSB) is $0$ the mathematics seems trivial. If you move the bits to the right it's a division by two because every number is divided by two (maybe floor since we lose the final bit sometimes if it's 1). With negative numbers using 2s complement it seems more complicated. We want -6 -> -3. Intuitively I would have assumed to "double" the positive part $pos$ but that doesn't quite work and results in left shift on $pos$ anyway. So no.

I've worked out a couple (many?) examples and wrote the equations but I can't seem to figure out the pattern. Why is a right bit arithmetic where you "carry the MSB" work with the intended semantics (divide by $2^k$ or multiply by $2^k$) for both positive and negative representations of numbers?

I've read related questions but I am still confused:

JMP
  • 21,771
  • There are lots of levels of why it's true. Would you just like a proof by algebra bashing? A more "conceptual" reason I'd mention is that n >> k == ~((~n) >> k), where ~n is the complementation operator. In two's complement, we have ~n == -1 - n. So from this you can pretty much deduce the result for negative numbers straight away. Another way to think about two's complement is "binary strings that go infinitely far left, but are always eventually all ones or all zeroes". The $2$-adic metric is then a meaningful sense in which $\dots 111 = -1$. – Izaak van Dongen Mar 09 '24 at 01:07
  • Finite-length two's complement arithmetic is a bit like this set, where the MSB is just used to store what the remaining infinitely many bits are. This makes it clear why the MSB should be carried in this way when doing a right shift. Unfortunately it's hard to make left shifts behave well for finite space, because there's just not enough space to store the outputs! So the natural setting to talk about abstract properties of left shifts is really the infinite strings. I think Python's bit-shifting is actually basically an implementation of this. – Izaak van Dongen Mar 09 '24 at 01:10
  • Using your example of $4$-bit negative number $-6$, or $1010_2$ in two's complement. This bit string as unsigned number is $-6+2^4$; logical right shifting once gives $\left\lfloor\frac{-6+2^4}2\right\rfloor=\left\lfloor\frac{-6}2\right\rfloor +2^3$; restoring the MSB for arithmetic shift gives $2^3+\left\lfloor\frac{-6}2\right\rfloor +2^3 = \left\lfloor\frac{-6}2\right\rfloor +2^4$. This is the number when interpreting the resultant bit string as unsigned; as two's complement the result is $\left\lfloor\frac{-6}2\right\rfloor +2^4 -2^4= \left\lfloor\frac{-6}{2}\right\rfloor$. – peterwhy Mar 09 '24 at 03:22
  • When performing arithmetic right shift once, using your $x$ and $N$, $$\begin{align} x\gg1&=a_{N-1}\left(-2^{N-1}+2^{N-2}\right)+\left\lfloor\frac{pos}2\right\rfloor\ &= -a_{N-1}2^{N-2} +\left\lfloor\frac{pos}2\right\rfloor\ &= \frac{neg}2 +\left\lfloor\frac{pos}2\right\rfloor \end{align}$$ – peterwhy Mar 09 '24 at 03:47

2 Answers2

1

Since it seems that you haven't understood how 2-complement works, I'll explain it first, then I'll explain how right shift works for 2-complement negative numbers.

How 2-complement works

Let $N$ be the number of binary digits used for storing a number. For every $n\in\mathbb{Z},N\in\mathbb{N}^+$ there exists a unique $k \in \mathbb{Z}$ and a unique finite sequence $(d_i)$, $d_i\in\{0,1\}$, $0\leq i\leq N-1$ such that $$n = 2^N k+ \sum_{i = 0}^{N-1}{2^id_i}$$ This can simply be proven inductively. Now you see that $d_i$ is the $i$-th digit of the binary system, which are stored in the memory. $k$, however, is not stored, hence it must be chosen. For unsigned integers, the choice is naturally $k = 0$, leading to

$$n = \sum_{i = 0}^{N-1}{2^id_i}$$

A consequence is that $n$ can only represented for $0 \leq n \leq 2^N-1$. For signed integers, this is clearly problematic because there isn't any negative integer at all. We also want a way to represent them in such a way that their difference from the unsigned system is minimal.

So how do we represent negative numbers? Well, the fundamental property of negative numbers is that $$a+(-a)=0$$

Now, let $\bar{a} = 2^N - a$, we have that: $$a + \bar{a} = 2^N = 2^N + 0$$ While $a+\bar{a} > 0$, its N binary digits are $equal$ to those of $0$. By ignoring the fact that we made an overflow ($k$ increased by $1$), we made $b$ equavilent to $-a$. But, wait for it, we can also prove it works for multiplication! $$a\bar{b} = a(2^N-b) = 2^Na + a(-b)$$ So we managed to represent negative numbers without changing how we do addition and multiplications, the two essential operations on integers! Now we need to choose the values for which the number is positive. As you have known, this is chosen via the MSB. Let $u(n)$ be the usigned number which have the same digits as signed integer $n$, then that means: $$ \begin{align} &&&\begin{cases} u(n) = n, &0\leq u(n) \leq 2^{N-1}-1\\[10pt] u(n) = n+2^N, &2^{N-1} \leq u(n) < 2^N\\ \end{cases}\\[10pt] &\Leftrightarrow&&\begin{cases} u(n) = n, &0 \leq n \leq 2^{N-1}-1\\[10pt] u(n) = n+2^N, &2^{N-1} \leq n < 0\\ \end{cases} \end{align} $$ consequently, the range of values is $-2^{N-1}\leq n \leq 2^{N-1}-1$. Additionally, exactly half of them are positive (perfectly balanced, as all things should be) and they can be easily extended to higher number of digits by repeating the MSB (try to prove that yourself) :)

Well we got the digits for negative numbers, now we need a way to calculate them on a circuit. Notice that: $$\begin{align}\bar{n} = 2^N - n &= 1+ (2^N-1)-n\\ &= 1 + \sum_{i = 0}^{N-1}2^i - \sum_{i = 0}^{N-1}{2^id_i}\\ &= 1 + \sum_{i = 0}^{N-1}{2^i(1-d_i)}\\ \end{align} $$ It's clear that $\sum_{i = 0}^{N-1}{2^i(1-d_i)}$ is the 1-complement of $n$, which is easy to do by flipping every bit. Then we just need to add 1. This is where the 2-complement thing comes from. Now we are ready to learn how right shift works

How right-shift works

Let $m$ be the result of shifting $n$ by $1$ digit to the right. For $n>0$, we have $$m = \sum_{i = 1}^{N-1}{2^{i-1}d_{i}}$$ Hence$$ 2m = \sum_{i = 1}^{N-1}{2^id_{i}} = n-d_0$$ Clearly, $m$ is approximately half of $n$.

For $n < 0$, we have:

$$u(m) = 2^{N-1} + \sum_{i = 1}^{N-1}{2^{i-1}}d_{i}$$ Where $u(m)$ is the unsigned counterpart of $m$. The $2^{N-1}$ term is there because we carried the MSB, which is $1$. Consequently $$m = u(m) - 2^N = \sum_{i = 1}^{N-1}{2^{i-1}d_i} - 2^{N-1}$$ Hence $$2m = \sum_{i = 1}^{N-1}{2^id_{i}} - 2^{N} = n - d_0$$ Thus $m$ is also nearly half of $n$ for $n<0$

ioveri
  • 1,196
  • 6
0

In two's complement, let the bit representation be $T=a_{N-1}\dots a_0$, with $a_{N-1}$ the most significant bit (MSB) with a value of $-2^{N-1}$, and $a_0$ as the least significant bit (LSB) with value $1$.

The numerical value of $|T|$ is the positive integer $S$ represented by $S=a_{N-2}\dots a_0$, where $T=-2^{N-1}+S$.

As $S+NOT(S)+1=2^{N-1}$, then $|T|=NOT(S)+1$, where $NOT(S)$ is the one's complement. Similarly, if $S$ is a positive integer, $-S = -2^{N-1} + NOT(S) + 1$.

So in order to halve $T$ (knowing that $T<0$) we can halve $NOT(S)+1$ by performing a logical right shift ($>>1$).

Note that the floor function has slightly unusual behaviour when changing from positive to negative odd numbers, $\lfloor \frac{5}{2}\rfloor = 2$, whereas $\lfloor \frac{-5}{2}\rfloor = -3$ for example, so converting back to two's complement needs to take this into consideration.

If $L=(NOT(S)+1)$ is odd, then $\frac{|T|}{2}=-2^{N-1} + NOT(L>>1)$, otherwise $\frac{|T|}{2}=-2^{N-1} + NOT(L>>1)+1$.

Examining the edge cases of $S=0$ and $S=2^{N-1}-1$ gives

$S=0, NOT(S)=2^{N-1}-1, NOT(S)+1=2^{N-1} (even), L>>1=2^{N-2}, NOT(L)=2^{N-2}-1$

Then $\frac{|T|}{2}=-2^{N-1} + 2^{N-2}=-2^{N-2}$ as required.

$S=2^{N-1}-1, NOT(S)=0,NOT(S)+1=1 (odd), L>>1=0, NOT(L)=2^{N-1}-1$.

Then $\frac{|T|}{2}=-2^{N-1} + 2^{N-1}-1=-1$ as required.

Note that bit $N-2$ is always set, therefore an arithmetic right shift is as defined in the literature.

JMP
  • 21,771