Binary Arithmetic & Two's Complement Lab

Visualize binary bit weights, explore signed representations, and step-by-step column arithmetic (addition, subtraction, and multiplication).

Loading interactive simulation...

One adder does subtraction too 🖖

In modern computers, negative integers are represented using Two's Complement. Under this representation, the most significant bit (MSB) simply acts as a negative weight: for an 8-bit integer, bit 7 represents -128 instead of +128. This mathematical mapping has a beautiful property: subtraction is identical to addition. For example, to calculate A - B, the CPU simply calculates A + (~B + 1), where ~B is the bitwise complement. This eliminates the need for separate subtraction hardware, allowing the Arithmetic Logic Unit (ALU) to use the same logic gate adder circuits for both addition and subtraction. One's Complement and Sign & Magnitude were historically used, but both suffer from duplicate representations of zero (positive and negative zero) and require more complex ALU control logic.

binary is just place value, base two 🖖

In everyday numbers each column is worth ten times the one to its right; in binary the factor is simply 2. So the bits carry (from the right) the weights 1, 2, 4, 8, 16, 32, … Reading a binary number means adding up the weights wherever a 1 sits: 1011 is 8 + 0 + 2 + 1 = 11. The tool's bit-weight display lets you toggle each bit and watch the running total, which is the secret behind every conversion here.

your CPU multiplies like a Russian peasant 🖖

The long multiplication here — doubling A and adding it wherever B has a 1 bit — is exactly "Russian peasant multiplication," a method already found on Egyptian papyri over 3000 years old. You halve one number (dropping any remainder) and double the other, then sum the doubled values wherever the halved number is odd. Halving and checking for oddness is literally reading off binary digits, so an ancient scribe and a modern ALU run the same algorithm.

EIGHT BITS, FOUR MEANINGS — WHICH ENCODING ARE YOU READING?

Which Binary Encoding Are You In?

A byte carries no clue about how to read it. The pattern 11010110 is 214, or −42, or −41, or −86, depending only on a convention agreed in advance — and the bits themselves cannot tell you which. Choose wrong and every step afterwards is wrong while every step still looks right. So the first question is never what the answer is, but what the top bit weighs. The four encodings below answer that four ways; the last two cases show why one of them won the hardware.

Unsigned — every column adds w₇ = +128 → 0…255
Two's complement — the top bit owes you 128 w₇ = −128 → −128…127
One's complement — negate by flipping every bit w₇ = −127, 0 = ±0
Sign & magnitude — the bit that is not a number w₇ = ±, 0 = ±0
Subtraction without a subtractor a − b = a + (¬b + 1)
Multiply by shifting and adding a × b = ∑ (a ≪ i)

01

Unsigned — every column adds

What you know: All eight weights are positive powers of two, 1 through 128. Nothing encodes a sign, so nothing can be negative: the range is 0 to 255 and all 256 patterns are in use.

How to read it: w₇ = +128 → 0…255

Worked example: 85 + 11 → 01010101 + 00001011 = 01100000 = 96, with carries rippling up out of the low columns. Push further and 214 + 100 gives 58 in eight bits — the true 314 less 256, with the missing 1 sitting in the carry out.

Open this case: Unsigned add
Unsigned — every column adds. All weights positive: the eight columns simply add, 0 through 255. All eight weights are positive powers of two, 1 through 128. Nothing encodes a sign, so nothing can be negative: the range is 0 to 255 and all 256 patterns are in use.
All weights positive: the eight columns simply add, 0 through 255.

02

Two's complement — the top bit owes you 128

What you know: Seven positive weights and one negative: bit 7 is worth −128 instead of +128. Nothing else changes, and the range moves to −128 through 127.

How to read it: w₇ = −128 → −128…127

Worked example: 11010110 decodes as −128 + 64 + 16 + 4 + 2 = −42. Add 10 (00001010) by ordinary column addition and you get 11100000 = −128 + 64 + 32 = −32. The very same eight bits are 214 in unsigned mode.

Open this case: Two's complement
Two's complement — the top bit owes you 128. Bit 7 weighs −128, so 11010110 is −42 — the bits unsigned mode calls 214. Seven positive weights and one negative: bit 7 is worth −128 instead of +128. Nothing else changes, and the range moves to −128 through 127.
Bit 7 weighs −128, so 11010110 is −42 — the bits unsigned mode calls 214.

03

One's complement — negate by flipping every bit

What you know: Bit 7 weighs −127. A negative number is the bitwise inverse of its magnitude, so −42 is 11010101 and not 11010110, and the range is symmetric: −127 through 127.

How to read it: w₇ = −127, 0 = ±0

Worked example: −42 is 11010101, the inverse of 00101010. Adding 10 gives 11011111 = −127 + 64 + 16 + 8 + 4 + 2 + 1 = −32, which is right here only because nothing carried out of the top. Try −42 + 50 instead: the plain sum reads 7, one short, and the carry out has to be added back in to reach 8.

Open this case: One's complement
One's complement — negate by flipping every bit. −42 is just 42 inverted, and 11111111 is a second, negative zero. Bit 7 weighs −127. A negative number is the bitwise inverse of its magnitude, so −42 is 11010101 and not 11010110, and the range is symmetric: −127 through 127.
−42 is just 42 inverted, and 11111111 is a second, negative zero.

04

Sign & magnitude — the bit that is not a number

What you know: Bit 7 is a pure flag carrying no weight whatsoever: 0 means positive, 1 means negative, and the low seven bits hold an ordinary magnitude from 0 to 127.

How to read it: w₇ = ±, 0 = ±0

Worked example: −42 is 10101010: the sign bit set, then 42 as 0101010. This is how people write numbers, and it is the one encoding of the four where handing both operands to a plain adder is simply wrong — 10101010 + 00001010 comes out as 10110100, which decodes as −52 rather than −32.

Open this case: Sign & magnitude
Sign & magnitude — the bit that is not a number. The sign bit carries no weight — and a plain adder returns −52 instead of −32. Bit 7 is a pure flag carrying no weight whatsoever: 0 means positive, 1 means negative, and the low seven bits hold an ordinary magnitude from 0 to 127.
The sign bit carries no weight — and a plain adder returns −52 instead of −32.

05

Subtraction without a subtractor

What you know: Two's complement with the operation set to subtract. The hardware owns no subtract circuit: it negates the second operand and adds.

How to read it: a − b = a + (¬b + 1)

Worked example: 42 − 58 → invert 00111010 to 11000101, add 1 to get 11000110, which is −58. Now add 00101010 to it: 11110000, and that decodes as −128 + 64 + 32 + 16 = −16.

Open this case: Subtract by adding
Subtraction without a subtractor. Invert, add one, then add: 42 + (−58) lands on −16. Two's complement with the operation set to subtract. The hardware owns no subtract circuit: it negates the second operand and adds.
Invert, add one, then add: 42 + (−58) lands on −16.

06

Multiply by shifting and adding

What you know: Unsigned mode with the operation set to multiply. Every 1 bit in the second operand contributes a copy of the first, shifted left by that bit's position.

How to read it: a × b = ∑ (a ≪ i)

Worked example: 13 × 5 → the 5 is 00000101, so bits 0 and 2 are set. That contributes 13 shifted by nothing (00001101 = 13) plus 13 shifted twice (00110100 = 52), and 13 + 52 = 65 = 01000001.

Open this case: Shift and add
Multiply by shifting and adding. 5 has bits 0 and 2 set, so 13 and 52 are the only rows that count. Unsigned mode with the operation set to multiply. Every 1 bit in the second operand contributes a copy of the first, shifted left by that bit's position.
5 has bits 0 and 2 set, so 13 and 52 are the only rows that count.

Problem solved in full

  1. Two separate overflow flags for 42 converted to eight bits 6 steps

    Convert 42 to eight bits two different ways, then work out why a CPU carries two separate overflow flags when it only has one adder.

    1. Positional notation is a sum of powers, so the direct route is to find which powers of two are present. Three of them, and the bit pattern falls out.

    2. The mechanical route gives the same answer without any searching. Divide by two repeatedly and the remainders are the bits, least significant first — read the column upwards.

    3. Negation in two's complement is invert-then-increment, and the result equals 256 − 42. That is the whole trick: arithmetic modulo 256, with the top half relabelled as negative.

    4. Now the flags. Carry out is a property of the top bit position; overflow is a disagreement between the carry into the sign bit and the carry out of it.

    5. Take a pair where the two flags disagree. No carry leaves the byte, so unsigned arithmetic is fine, but the sign bit flipped — the signed answer is wrong by 256.

    6. Reverse it with a pair that carries but does not overflow, and the case for two flags is closed.

    Answer

    Because the same bits mean two different numbers, and only the programmer knows which. 0110 0100 + 0011 0010 = 1001 0110 produces no carry out of bit 7, so C = 0 and an unsigned reading of 100 + 50 = 150 is perfectly correct. Read the same result as two's complement and it is −106, which is nonsense, and V = 1 says so. Add 200 + 100 instead and the flags swap: C = 1, V = 0. The adder does not know and does not care — it computes one sum and raises both alarms, and the instruction the compiler picks afterwards decides which one is a bug. This is why C and C++ leave signed overflow undefined and define unsigned wraparound: the hardware distinguishes them, and the language chose to expose that.

References (1)

Example problems

  • Unsigned add - 85 + 11 in binary with carry column propagation.
  • Two's complement - Two's complement: 11010110 reads as -42, and -42 + 10 = -32.
  • One's complement - One's complement: the top bit weighs -127, so -42 is 11010101.
  • Sign & magnitude - Sign & magnitude: the top bit is pure sign, so -42 is 10101010.
  • Subtract by adding - 42 - 58 = -16, illustrating how subtraction is added using negative MSB weight.
  • Shift and add - 13 × 5 = 65 via shift-and-add binary long multiplication.