Negative numbers and subtraction
Two's complement, and one block that does both
Two's complement encodes negative numbers so the same adder can subtract: to compute A minus B, add A to the bitwise-inverted B with a carry-in of 1. Adding one XOR gate per bit turns a plain adder into a combined adder/subtractor.
The 8-bit adder adds. To get subtraction we could design a whole separate borrow circuit, but there is a far nicer route: represent negative numbers in two's complement, and subtraction becomes addition with two tiny tweaks. The same eight full adders then do both jobs, steered by a single control bit.
Two's complement: how negatives fit on the same wires
With 8 wires you have 256 bit patterns. Two's complement spends half of them on negatives: patterns with the top bit
0 are 0 to 127 as usual, and patterns with the top bit 1 stand for -128 to -1. The rule to negate a number is: flip every bit, then add 1. So +1 is 0000 0001; flip to 1111 1110, add 1 to get 1111 1111, which is -1. The beauty is that ordinary binary addition then just works across the sign: 1 + (-1) adds 0000 0001 + 1111 1111 and the carry falls off the top, leaving 0000 0000.Why "flip and add 1" works: flipping all bits gives
255 - B (the ones' complement). Adding 1 makes 256 - B. In 8-bit arithmetic the 256 wraps to 0, so A + (256 - B) lands on A - B. Subtraction is addition of the negation, and the negation is just inversion plus a carry-in of 1.Turning the adder into an adder/subtractor
Here is the trick. Put one XOR gate on each
B wire before it enters the adder, and feed a shared control line SUB to the other input of every XOR. Recall from the XOR lesson that X XOR 0 = X and X XOR 1 = NOT X: the XOR is a controllable inverter. When SUB = 0 the B bits pass through unchanged and you get A + B. When SUB = 1 every B bit is flipped, and if you also feed that same SUB into the adder's carry-in (the +1), the adder computes A + (NOT B) + 1 = A - B.- Take the 8-bit adder you built.
- On each
Biwire, insert an XOR: one input isBi, the other is the sharedSUBline. The XOR output feeds the adder. - Wire
SUBinto the adder's carry-inCINas well (that supplies the+1). SUB = 0givesA + B;SUB = 1givesA - B. One control bit picks the operation.
Try it
Negate
+6 by hand using two's complement (flip every bit, then add 1), starting from 0000 0110. Then check: add your result to +6 and confirm you get zero.Answer
Flip
0000 0110 to 1111 1001, then add 1: 1111 1010, which is -6. Check by adding to +6: 0000 0110 + 1111 1010 = 1 0000 0000. The carry falls off the top of the 8 bits, leaving 0000 0000, exactly zero. That is why +6 and its two's complement cancel.ADDSUB8): eight XOR gates invert B under control of SUB, which also seeds the carry-in. SUB = 0 adds, SUB = 1 subtracts. Open it in the lab; compute 5 - 3 and read 2, then 3 - 5 and read the two's-complement pattern for -2.When you compute
3 - 5 the result 1111 1110 is -2 in two's complement. The probes show the raw bits; reading them as signed is a matter of interpretation, not extra hardware. The same 1111 1110 is 254 if you decide the byte is unsigned. The CPU stores bits; signedness lives in how you read them.A harder road: sign-magnitude subtraction
Two's complement is not the only way to write negatives. The oldest scheme, sign-magnitude, is the one people use by hand: reserve the top bit as a pure sign flag (
0 for positive, 1 for negative) and let the remaining bits carry the plain unsigned magnitude. With one sign bit and four magnitude bits, +6 is 0 0110 and -6 is 1 0110, so only the sign bit moves and the magnitude 0110 stays put. Two's complement, by contrast, rewrites every bit to negate. Sign-magnitude is easy to read, but it pushes the effort onto the hardware, and subtraction is where that shows.A plain magnitude subtractor (the same adder/subtractor from above, run in subtract mode) returns the right answer only when the first operand is the larger one. Give it
M - S with M greater than or equal to S and it hands back M - S cleanly. Give it M - S with M smaller than S and it underflows: it tries to borrow past a top bit that is not there, and the magnitude bits come out wrong.Watch the underflow. Suppose you want
6 - 9 with 4-bit magnitudes. A 4-bit subtractor computing 6 - 9 cannot fit -3 into four magnitude bits, so it wraps: the output bits come out 1101 (which reads as 13) with a borrow off the top, not the 3 you wanted. Sign-magnitude has a second quirk as well: it holds two zeros, 0 0000 for +0 and 1 0000 for -0, which downstream logic must treat as equal. Two's complement dodges both problems: its bits are already correct for any order of operands, and it has exactly one zero.The fix is to force the subtractor to always see the larger magnitude first, while remembering which input that was so you can set the sign. That is a compose-with-blocks job, four familiar parts wired in a row: a comparator, a pair of multiplexers, the subtractor, and one inverter.
- Compare. Feed both magnitudes into a comparator and read
A >= B, which is itsGToutput OR itsEQoutput. Call that lineAGE, for A greater-or-equal. - Swap. Send the two magnitudes through two multiplexers that share
AGEas their select line. One mux outputs the minuendM = AGE ? A : B; the other outputs the subtrahendS = AGE ? B : A. NowMis always the larger magnitude, soM >= Sholds by construction. - Subtract. Feed
MandSinto the subtractor. BecauseM >= S, it never underflows, and its output is the correct result magnitudeM - S. - Set the sign. The result is negative exactly when
Awas the smaller value, so the result's sign bit is simplyNOT AGE. Put it in front of the magnitude and you have the answer in sign-magnitude form.
Trace
6 - 9. The magnitudes are A = 0110 and B = 1001. The comparator sees 6 < 9, so AGE = 0. With AGE = 0 the muxes swap the inputs: M = B = 1001 (9) and S = A = 0110 (6). The subtractor computes 9 - 6 = 0011 (3) with no underflow this time. The sign bit is NOT AGE = 1, negative, so the result is 1 0011, which is -3, exactly right. Run it the other way as 9 - 6: now AGE = 1, the muxes leave M = 9 and S = 6 in place, the subtractor gives 0011, the sign is NOT 1 = 0, and the answer is 0 0011, +3.Try it
Using the compare, swap, subtract, sign recipe, work out
3 - 10 with 4-bit magnitudes. After the swap, which value is the minuend M? What magnitude comes out of the subtractor, and what is the sign bit of the result?Answer
The magnitudes are
A = 0011 (3) and B = 1010 (10). Since 3 < 10, AGE = 0, so the muxes swap: the minuend is M = B = 1010 (10) and the subtrahend is S = A = 0011 (3). The subtractor computes 10 - 3 = 0111 (7). The sign bit is NOT AGE = 1, negative. The result is 1 0111, which is -7, and indeed 3 - 10 = -7.Add up the cost. Sign-magnitude subtraction needed a comparator, two multiplexers, a subtractor, an inverter, and special care for
-0. The two's complement adder/subtractor at the top of this lesson needed one adder, one XOR per bit, and a single control wire, with no comparison and no swap: the same two numbers go in and the correct signed result comes out every time. That gap is exactly why nearly every processor stores signed integers in two's complement, and reserves sign-magnitude for places like the sign of a floating point number, where a one-bit sign flip is precisely what you want.Frequently asked
How does a computer subtract using two's complement?
It turns subtraction into addition:
A - B = A + (NOT B) + 1. To compute A - B, the hardware inverts every bit of B and adds 1 (by setting the carry-in to 1), then the ordinary 8-bit adder does the rest. There is no separate borrow circuit.Why does "flip every bit and add 1" negate a number?
Flipping all bits of
B gives 255 - B (the ones' complement); adding 1 makes 256 - B. In 8-bit arithmetic the 256 wraps to 0, so A + (256 - B) lands on A - B. Negation is just inversion plus a carry-in of 1.How is a subtractor different from a plain adder?
It is the same adder plus one XOR gate on each
B wire, all fed by a shared control line SUB. Since X XOR 0 = X and X XOR 1 = NOT X, the XOR is a controllable inverter: SUB = 0 passes B through for A + B, while SUB = 1 flips B and (feeding SUB into the carry-in too) computes A - B. One control bit picks the operation.How can the same 8 wires hold a negative number?
Two's complement spends half of the 256 patterns on negatives: top bit
0 means 0 to 127, top bit 1 means -128 to -1. The CPU only ever stores bits; signedness lives in how you read them, so 1111 1110 is -2 signed or 254 unsigned with no extra hardware.How does sign-magnitude subtraction work?
Sign-magnitude stores a number as a sign bit plus a plain magnitude, so subtracting two of them takes several blocks: compare the two magnitudes, use multiplexers to send the larger one into the subtractor as the minuend, subtract to get the result magnitude, then set the result's sign from which input was larger. A bare magnitude subtractor is wrong whenever the first operand is the smaller one, which is why the compare-and-swap step is needed.
Why did two's complement replace sign-magnitude for integers?
Two's complement turns subtraction into one addition with a bit-flip and a carry-in, using a single adder and no comparison, and it has just one zero. Sign-magnitude subtraction instead needs a comparator, two multiplexers, a subtractor, an inverter, and special handling for its two zeros (
+0 and -0). Two's complement is far less hardware for the same result, so processors use it for signed integers and reserve sign-magnitude for places like the sign of a floating point number.Every lesson here builds toward one thing: a working CPU, from the transistor up.
Open the free lab →