3.2 Two’s Complement
3.2.2 Multiplication in Two’s Complement
When multiplying two numbers in Two’s Complement encoding, we need to follow a few steps. For maximum generality, we assume that our numbers have lengths m and n, respectively.
1. Increase the bitlength of both numbers through sign extension (as described above) to length m + n.
2. Perform regular binary multiplication of the two resulting numbers. Note that to add the individual rows, we must use the addition function from above.
Example 3.3: As an example, we multiply −3 = 101 (m = 3) and 7 = 0111 (n = 4): First, we sign extend both numbers to length n+m = 4+3 = 7 to obtain −3 = 1111101 and 7 = 0000111. We then compute (always only performing addition up to the cutoff-position indicated by the vertical dashed line):
1 1 1 1 1 0 1 · 0 0 0 0 1 1 1 | 1 1 1 1 1 0 1 | 1 1 1 1 0 1 | 1 1 1 0 1 | 0 0 0 0 | 0 0 0 | 0 0 | 0 1 1 0 1 0 1 1
This correctly yields 1101011 = −21.
Whenever we refer to the addition of rows during multiplication, we are referring to the rows of the multiplication matrix (see Definition 2.2) as in the above example, which has 7 rows of lengths 7, 6, . . . , 1, respectively.
3.2.2.1 Removing Redundancy
As can easily be seen, the above approach introduces redundancy because the same product is calculated several times, which may become costly if bit multiplication is an expensive operation. As a minimal example, consider the case for n = m = 2:
a1 a1 a1 a0 · b1 b1 b1 b0
a1· b0 a1· b0 a1· b0 a0· b0
a1· b1 a1· b1 a0· b1
a1· b1 a0· b1
a0· b1
Here, we can see that out of the 10 terms that occur
(generally: (n + m) + (n + m − 1) + · · · + 2 + 1 = (n + m) · (n + m + 1)
2 terms),
the term a0· b0 occurs once, and the terms a1· b0, a0· b1 and a1· b1 all occur three times.
As can easily be seen, we actually only have n · m different products, so we can save a significant amount of computation by avoiding this redundancy.
We now show in detail how to avoid computing the same product several times, which more than halves the effort of the matrix computation step by bringing it from (n+m)·(n+m+1)2 to n · m. To this end, we will think of the rows that are generated as an (n + m) × (n + m)
- matrix A (with some empty entries) indexed as A[i, j], where i refers to the row and j to the bit position in the row, i.e., 0 is on the right-hand side.
As an example for the case with n = m = 2 (where we write [i, j] instead of A[i, j]), we have the following multiplication matrix:
a1 a1 a1 a0 · b1 b1 b1 b0
[0, 3] [0, 2] [0, 1] [0, 0] [1, 3] [1, 2] [1, 1] [2, 3] [2, 2] [3, 3]
With this notation in place, we present the pseudocode instructions for reducing the number of computations in multiplying two numbers of lengths n and m in Algorithm 2.
Algorithm 2: Redundancy Reduction Input: an−1. . . a1a0, bm−1. . . b1b0 1 for 0 ≤ j ≤ m − 1 do 2 for 0 ≤ i ≤ n − 1 do 3 A[j, j + i] = ai· bj 4 end 5 for n + j ≤ i ≤ n + m − 1 do 6 A[j, i] = A[j, n + j − 1] 7 end 8 end 9 for m ≤ i ≤ n + m − 1 do 10 for i ≤ j ≤ n + m − 1 do 11 A[i, j] = A[i − 1, j − 1] 12 end 13 end Output: A
The output A is now the same multiplication matrix (see Definition 2.2) as we would obtain by straightforward computation, but we save some effort by computing it this way because we copy duplicate values rather than computing them anew for each position. The second step of summing up the rows of this matrix is then done as before.
Note that in the simpler case where one value is known, i.e., multiplication by a constant, we do not need to do quite as much work: For simplicity, we always assume that the input b is known. We again first need to do sign extension for Two’s Complement, but in the next step instead of having to compute n · m terms ai · bj as before, we can just copy
the string a for every bit that is 1 in b, shifting to the left with each bit. This way, we save n · m multiplications from the generation of the matrix and reduce the depth by one. Also, note that we now don’t need to add as many rows, as we only write down those that correspond to the non-zero bits in b. Thus, we only need to do hm(b) row additions, where hm(b) is the hamming weight of b. Of course, the complexity and multiplicative depth now depend on the value of b and are the same as for regular multiplication in the worst case. However, on average we will only have to do half as many row additions.
3.2.2.2 Effort
We now compute the effort of multiplying two numbers in Two’s Complement encoding. We use the above method to avoid redundancy, and also copy the bits above blank spaces to the result rather than padding the shorter row as presented in Section 2.4.2.2, which means we only have the effort of the shorter row length in the addition. As before, we add row 1 to row 2, then add that to the result of adding row 3 to row 4 etc., until we are left with the final result. Note that we disregard (i.e., do not compute) anything past the (m + n)th bit.
Example 3.4: Suppose we have generated the rows of our matrix as
a1 a1 a1 a1 a0 · b2 b2 b2 b1 b0 c4 c3 c2 c1 c0 d3 d2 d1 d0 e2 e1 e0 f1 f0 g0
with the appropriate values in the matrix as above. Then we perform the following steps:
• Row 1+Row 2:
c4 c3 c2 c1 c0
+ d3 d2 d1 d0
h4 h3 h2 h1 c0
The result is h4h3h2h1c0, where h4h3h2h1is the result of adding c4c3c2c1and d3d2d1d0.
Thus, we have the effort of one addition of length 4, and the result, denoted Row21,
has length 5.
• Row 3+Row 4:
e2 e1 e0
+ f1 f0
i2 i1 e0
The result is i2i1e0, where i2i1 is the result of adding e2e1 and f1f0. Thus, we have
the effort of one addition of length 2, and the result, denoted Row2 2, has length 3.
• Row2 1+Row2 2:
h4 h3 h2 h1 c0
+ i2 i1 e0
j4 j3 j2 h1 c0
The result is j4j3j2h1c0, where j4j3j2 is the result of adding h4h3h2and i2i1e0. Thus,
we have the effort of one addition of length 3, and the result, denoted Row3 1, has
length 5.
• Row3 1+Row 5:
j4 j3 j2 h1 c0
+ g0
k4 j3 j2 h1 c0
The result is k4j3j2h1c0, where k4 is the result of adding j4 and g0. Thus, we have
It is easy to see that for a length of n + m, we always have one addition each of length 1, 2, . . . , n+m−1. The reason is that the addition effort is always the length of the smaller of the two inputs, and the result has the length of the larger of the two, which thus gets input as the shorter input at some later point unless it is the final length n + m.
A row addition of length k has the same effort as a Two’s Complement addition of length k − 1 (recall the table in Section 3.2.1), as the sign extension has already been done in the matrix. Thus, for length 1, we only compute a0+ b0 (1 addition), and for length 2,
we compute c0 and c1 for a total cost of 3 additions, 1 multiplication and a depth of 1.
For all lengths ` larger than 2, we have a cost of 5(` − 1) − 2 = 5` − 7 additions, ` − 1 multiplications, and a depth of ` − 1. Note that to compute the rows of the matrix, we need m · n multiplications and a depth of 1.
Regarding depth, note that the matrix entries start with a depth of 1, and then the depth propagates through the addition. We always have depth(c0) = depth(c1) = 1 in each row
because c0 is copied from the longer row and c1 = a1 + b1. The first carry r2 = a1 · b1
has depth 2, which is thus also the depth of c2. (Since the result bit in the addition is
ci = ai + bi+ ri, we see that its depth is the maximum of the depth of the three input
bits.) As we continue, the carry ri increases by 1 with each bit to the left and the inputs
ai and bi also have depth at most i by the exact same reasoning for the addition that
yielded the respective input row. Thus, the result bit ci has depth i, and since our longest
row is m + n bits long, the maximum depth we get is m + n − 1.
In total, to multiply two numbers of lengths m and n in Two’s Complement encoding, we have an effort of:
• Additions: 1 + 3 +n+m−1P i=3 5i − 7 = 5(m2+n2)−19(m+n)2 + 5mn + 10 • Multiplications: m·n+1+n+m−1P i=3 (i−1) = m·n+ n+m−2 P i=1 i = m·n+(n+m−2)·(n+m−1)2 • Depth: m + n − 1