M Binary Digits, We Can Represent The 2: Signed Number Representations CS221, Mock
M Binary Digits, We Can Represent The 2: Signed Number Representations CS221, Mock
M Binary Digits, We Can Represent The 2: Signed Number Representations CS221, Mock
CS221, Mock
Sign/Magnitude Notation
Sign/magnitude notation is the simplest and one of the most obvious methods of
encoding positive and negative numbers. Assign the leftmost (most significant) bit to be
the sign bit. If the sign bit is 0, this means the number is positive. If the sign bit is 1,
then the number is negative. The remaining bits are used to represent the magnitude of
the binary number in the unsigned binary notation.
Example:
Binary Value
0000 +0
0001 +1
0010 +2
0011 +3
0100 +4
0101 +5
0110 +6
0111 +7
1000 -0
1001 -1
1010 -2
1011 -3
1100 -4
1101 -5
1110 -6
1111 -7
Looking at the list you should notice an immediate peculiarity; there are two
representations for zero! There is positive zero, and negative zero. This can cause
complications for computers checking numbers for equality. Another disadvantage is
performing addition or subtraction – we require a special consideration of both signs of
the numbers to properly compute the operation. Because of these drawbacks, sign-
magnitude is rarely used for representing integers.
Radix Complementation – Two’s Complement
Radix complementation is used to represent signed quantities and is based on the ideas of
modular arithmetic. In modular arithmetic, there is a value called the Modulus (M) which
when added to or subtracted from a number, does not change its value.
Using four bits, the largest positive number we can represent is +7 since the first bit must
be a 0 to denote positive.
For a negative value for A, the sign bit, An-1 is one instead of zero. The remaining n-1 bits
are used to represent the negative integers from –1 to –2n-1. Note that we will have the
ability to represent one additional negative integer than positive integers, because we’re
using up one of the patterns starting with 0 to represent 0.
We would like to assign the negative integers to the available bit patterns in a way that
facilitates straightforward arithmetic. A method that does this is to use the following
formula:
n−2
Val = −2 n −1
An −1 + ∑ 2 i Ai
i =0
Consider a positive number. In this case, An-1 is zero. We end up with only the
summation of the remaining terms.
Now consider a negative number. The An-1 term is one, so we must add in –2n-1 . Now
consider if all of the remaining bits are all one’s. These will all add up to be +2n-1 -1. It
will be one smaller than the negative value; e.g. 1111 = yields –23 + 7, or –8 + 7 = -1.
No matter how many bits we have, if they are all ones, we will end up with –1.
Now consider if all of the bits are one’s except for the rightmost bit. We have the same
case as before, except the positive value will be +2n-1 –2 since we just subtracted one
from the positive value. When we add this to the negative value, we end up with –2.
The end result is we are counting backwards with the negative values, instead of counting
forward as with positive values. This is shown in the “circle” below:
This representation has the benefit that if we start at any number on the circle, we can add
positive k (or subtract negative k) from that number by moving k position clockwise or
counterclockwise. If an arithmetic operation results in traversal of the point where the
endpoints are joined, an incorrect answer is given. However, we are guaranteed that if
we add a positive and a negative value together, we will result in a value that is possible
to represent using the number of bits available.
To summarize, two’s complement lets us have only one representation for zero and
allows us to easily perform arithmetic operations without special cases for sign bits.
If we are given a decimal value, A, that we want to represent in two’s complement, there
is an easy way to do it:
If you are given a binary value in two’s complement and want to know what the value is
in decimal, then the process is to:
What is the decimal value of the two’s complement binary value 11100?
Leftmost bit is 1, so flip bits: 00011
Add one : 00100
This is 4, so the answer is –4.
What is the decimal value of the two’s complement binary value 11011?
Leftmost bit is 1, so flip the bits: 00100
Add one: 00101
This is 5, so the answer is –5
Why does this procedure of flipping the bits and adding one work? We won’t prove it (a
good way of doing so is by going over the Modulus definition of two’s complement).
However, to give you what is hopefully a convincing argument look once again at the
table below:
This table is arranged so that each row has the binary representation if the bits are
flipped. For example, 0000 flipped is 1111. However, 0000=0 while 1111=-1. The
numbers are off by one. If you look at each row, every value is off by one. This is why
after we flip the bits of a negative representation, if we add one, we get back the
magnitude of the negative value.
Computer Arithmetic
When the computer performs mathematical operations, these are executed inside the
ALU (Arithmetic Logic Unit). To some degree, everything else inside the computer is
there to service the ALU. ALU’s today can handle integers and many also handle
floating point (real) numbers. Some systems have a separate FPU (Floating Point Unit)
instead of bundling this with the ALU. For example, older Intel processors had a
separate math co-processor on a separate chip.
As shown in the picture above, the control unit determines when/what data the ALU gets.
Registers feed data into the ALU, and the ALU in turn outputs the result of computations
to registers and also to flags that will contain critical information regarding the status of
the arithmetic operation (e.g., could indicate if it was successful). The flags are typically
stored as bit values on a “flags” register.
Addition and Subtraction
Addition in two’s complement proceeds just like normal addition you would do with
decimal numbers, except instead you are adding with binary values. Each digit is added
using the following rules
0+0=0
1+0=1
1 + 1 = 0 (carry of 1 to next column)
1 + 1 + 1 = 1 (carry of 1 to next column)
There may be a carry beyond the end of the calculation, which is ignored.
However, we can’t ignore the possibility of overflow. This occurs when we try to
represent a value that is too large to hold in the number of bits available.
0010 (+2)
+ 1001 (-7)
------
1011
There is no overflow since we added a positive and negative number.
To convert 1011 to decimal, note the leading 1 indicating a negative value.
Flip the bits to get 0100, add 1 to get 0101, and the result is –5.
1111 (-1)
+ 1001 (-7)
------
11000
We discard the last carry of 1, giving us 1000.
There is no overflow since we added two negative numbers and got a negative one.
To convert 1000 to decimal, note the leading 1 indicating a negative value.
Flip the bits to get 0111 , add 1 to get 1000, and the result is –8.
0001 (+1)
+ 0111 (+7)
------
1000
There is overflow since we added two positive numbers and got a negative result.
In the ALU, the results of the overflow (and the carry) are stored in the flags register.
After performing an addition, we should check the flags register to make sure the
resulting data is valid.
+3 = 0011
flip bits: 1100
add one: 1101
1101 is –3 in two’s complement
We would then perform the addition routine as described above. One hardware design to
perform these tasks are shown below:
Integer Multiplication
Multiplying two integers together is a bit more complicated than addition. Note that we
could perform multiplication through repeated addition – the downside is that this will be
very slow.
First, multiplying (or dividing) by two on binary numbers is easy. Multiplying or
dividing a decimal number by ten is just a matter of moving the decimal point around.
The same happens with binary numbers when multiplying or dividing by two:
With integers, we have a fixed decimal point we can’t move around. So instead of
moving the decimal point, we can get the same result by shifting the bits left or right,
putting a 0 in at the end, where each bit shift results in a power of 2:
How about multiplying by arbitrary values? We can use the same paper-and-pencil
technique you probably learned in elementary school to multiple numbers, if they are
both positive. Multiplication on unsigned binary numbers is shown below:
We could build circuitry to perform these tasks. The problem arises when multiplying
two’s complement values. In the example below, if we consider values as regular
unsigned binary then everything works ok. However, to make it work for negative
values, we must make the partial products negative:
It turns out there is a different method that is faster and doesn’t need this final
transformation step. It is called Booth’s algorithm and is widely implemented.
Booth’s Algorithm
Booth’s algorithm is shown in the flowchart below. The multiplier and multiplicand are
placed in the Q and M registers, respectively. There is also a 1 bit register placed
logically to the right of the least significant bit (Q0) of the Q register and designated Q-1.
the results of the multiplication will appear in the A and Q registers.
An example is shown below:
In the example above, we are multiplying 7 * 3. An arithmetic shift is when we shift the
bits, but leave the leftmost or rightmost bit as-is. For multiplication, this will preserve the
sign bit. For example, an arithmetic shift right on 10010 results in 11001. We have
shifted all of the bits to the right, but kept the leftmost bit as a 1 instead of putting a zero
in it. If the leftmost bit was a 0, it would remain 0 after the shift.
In the example, initially Q contains 3 and M contains 7. A and Q-1 are set to 0. Since the
values are 4 bits, we will have 4 cycles. In the first cycle, Q0Q-1 are equal to 10. Using
the flowchart, this results in setting A = A-M , or 0-7 = -7. Next we arithmetically shift
A,Q,and Q-1 as if they were all connected. In the second cycle, Q0Q-1 are equal to 11.
Using the flowchart, we simply perform an arithmetic shift and continue to the third
cycle. In the third cycle, Q0Q-1 are equal to 01. Using the flowchart, we set A=A+M and
arithmetic shift again. Finally, in the fourth cycle, we simply perform a shift.
The end result is in AQ which equals 00010101. This is 21 in decimal. You can verify
that this algorithm also works for negative multipliers.
Why does this work? Here is a brief rationale. Consider a positive multiplier with one
block of one’s surrounded by zero’s. Multiplication can be achieved by adding
appropriately shifted copies of the multiplicand, as in the example of multiplying
unsigned binary numbers:
2j + 2j-1 + … + 2i = 2j+1 – 2i
For example:
01111 = 23 + 22+ 21 + 20 = 15
This is the same as:
10000 – 00001 = 16 –1 = 15
We can generalize this approach for cases with more than one block of ones:
Booth’s algorithm conforms to this scheme by performing a subtraction when the first 1
of the block is encountered (10) and an addition when the end of the block is encountered
(01). A similar argument applies for a negative multiplier.
Integer Division
Division is a bit more complex than multiplication but is based on the same principles as
the paper-and-pencil division technique:
00001101 Quotient
Divisor 1011 10010011 Dividend
1011
001110
Partial 1011
Remainders
001111
1011
100 Remainder
The book contains more information describing the steps that must be taken to perform
integer division (and to perform it more efficiently, too).