Skip to content
Computer Systems

Computer arithmetic: adders, carry lookahead and multiplication

The full adder with proof, ripple carry, carry lookahead, two's complement subtraction, overflow and flags, multipliers.

The arithmetic logic unit does its sums with logic gates. In Foundations of Computer Science we saw how numbers are represented in binary and in two’s complement; here we see how hardware adds, subtracts, detects errors and multiplies, and why the way carries propagate decides a processor’s speed.

The full adder

Adding two binary numbers column by column requires, for each bit, adding three digits: the two bits A and B and the carry C_{in} from the previous column. The result is a sum bit S and a carry C_{out} for the next column.

Theorem.

    \[ S = A \oplus B \oplus C_{in},\qquad C_{out} = AB + C_{in}(A \oplus B) \]

Proof. Check it on the truth table of the eight combinations. S is 1 when the number of inputs at 1 is odd (1 or 3), which is the definition of the exclusive OR of three bits. C_{out} is 1 when at least two inputs are 1: either A and B both are (AB), or exactly one of them is (A \oplus B) and C_{in} is too. The two cases are disjoint and cover every possibility. ∎

Full adder built from logic gates and four-bit ripple-carry adder
At the top the full adder: two XOR gates produce the sum, two AND gates and an OR gate produce the carry. At the bottom four full adders in a row: the carry of each enters the next, from right to left.

Carry propagation

Placing n full adders in a row, with each carry output connected to the next carry input, gives the ripple-carry adder. It is simple, but slow: the most significant bit is not valid until the carry has travelled the whole chain. If each stage adds a delay of two gates, a 64-bit adder accumulates 128, far too many for a processor running at a few gigahertz.

Carry lookahead

For each column two signals are defined that depend only on A_i and B_i:

    \[ g_i = A_iB_i\ \ \text{(generate)},\qquad p_i = A_i \oplus B_i\ \ \text{(propagate)} \]

The column generates a carry on its own if both bits are 1; it propagates the incoming one if exactly one is 1. So c_{i+1} = g_i + p_ic_i, and substituting:

    \[ c_2 = g_1 + p_1g_0 + p_1p_0c_0,\qquad c_3 = g_2 + p_2g_1 + p_2p_1g_0 + p_2p_1p_0c_0 \]

Each carry is computed directly from the inputs, with two levels of gates, without waiting for the previous ones. The gates become very wide as n grows, so one works in groups of 4 bits and repeats the idea hierarchically: the delay grows as \log_2 n instead of n. The adders of modern processors are variants of this idea (prefix adders, such as Kogge-Stone).

Subtraction and overflow

In two’s complement, -B is obtained by inverting all bits and adding 1. So

    \[ A - B = A + \overline{B} + 1 \]

and the same adder also subtracts: just put XOR gates on the B inputs (to invert them when needed) and set the initial carry c_0 to 1. This is one reason two’s complement has displaced every other representation of negative numbers.

Overflow. Adding two numbers of the same sign, the result can fall outside the representable range: with 8 bits, 100 + 100 = 200 exceeds 127 and appears as −56. It is recognised because the sign of the result differs from that of both addends; in hardware, equivalently, the carry into the most significant bit differs from the carry out of it: V = c_{n} \oplus c_{n-1}.

The ALU reports the outcome of operations with a few status bits, the flags: Z (zero result), N (negative), C (carry, useful for unsigned numbers), V (overflow, for signed ones). The conditional branches of architectures that use them rely on these bits.

Multiplication

Binary multiplication is simpler than decimal: each partial product is either the multiplicand or zero, depending on the multiplier bit, shifted to the corresponding position. The n partial products are then added.

  • The slowest method, shift and add, uses a single adder for n cycles.
  • Tree multipliers add all partial products together with adders arranged in a tree (Wallace trees), and multiply two 64-bit numbers in a few clock cycles.

Division is harder and is done with iterative algorithms producing one or more quotient digits per cycle: that is why, in speed-critical programs, compilers replace divisions by constants with multiplications and shifts. Floating-point numbers (IEEE 754 standard, Numerical Analysis lesson) have a dedicated unit, which aligns the exponents, operates on the mantissas and normalises the result.

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x
()
x