1. Home
  2. Computer Organization & Architecture
  3. Two's Complement

Two's Complement

How computers store negative numbers. Invert the bits, add 1, and watch the sign bit take a negative weight.

Interactive 3DBeginner9 min readCOAUpdated

Drag to rotate · Right-drag to pan · Click, then scroll to zoom · Space play · ←→ step

What's happening

Pseudocode

    Try this in the 3D model

    • Convert −37 in 8 bits. Write down the three rows before pressing Convert again, then compare.
    • Convert −128. Why does inverting and adding 1 give back the same bit pattern as the magnitude?
    • Switch to 4 bits and try −8, then 7. These are the two ends of the range.
    • Try a positive number such as 37. What changes compared with −37?

    Why negative numbers need a trick

    A register is just a row of bits. To store −5 we have to agree on which bit pattern means −5. The method that won is two’s complement, because it lets the CPU use one adder for positive and negative numbers alike.

    The weights idea

    In an 8-bit unsigned number the bit weights are 128, 64, 32, 16, 8, 4, 2, 1. In two’s complement the leftmost weight becomes negative: −128, 64, 32, 16, 8, 4, 2, 1.

    So 11111011 = −128 + 64 + 32 + 16 + 8 + 2 + 1 = −5.

    Negating a number

    to get −x:
        1. write x in binary (n bits)
        2. invert every bit        (one's complement)
        3. add 1

    Example: −37 in 8 bits

    Step Bits
    37 in binary 00100101
    Invert 11011010
    Add 1 11011011

    Check: −128 + 64 + 16 + 8 + 2 + 1 = −37.

    Range

    With n bits you can store −2ⁿ⁻¹ to 2ⁿ⁻¹ − 1. For 8 bits that is −128 to 127, and for 4 bits −8 to 7. There is only one zero (0000), which is why the range is not symmetric.

    Subtraction for free

    To compute a − b the CPU adds a to the two’s complement of b. No separate subtractor is needed, only the adder shown in the ripple-carry adder lesson.

    Code

    def twos_complement(x, bits=8):
        return format(x & ((1 << bits) - 1), f'0{bits}b')
    
    def from_twos_complement(s):
        n = len(s)
        value = int(s, 2)
        return value - (1 << n) if s[0] == '1' else value
    
    print(twos_complement(-37))              # 11011011
    print(from_twos_complement('11111011'))  # -5

    Common mistakes

    • Forgetting to add 1 after inverting. Inverting alone gives the one’s complement, which is off by one.
    • Using too few bits. −37 does not fit in 6 bits (range −32 to 31).
    • Treating the sign bit as “just a minus sign”. It is a bit with weight −2ⁿ⁻¹, and the other bits change meaning too.
    • Mixing up the range: −128 exists in 8 bits, but +128 does not.

    Complexity at a glance

    Case / operationTimeWhy
    Negate a numberO(n)Invert n bits and add 1, which may ripple a carry through all n bits.
    Add or subtractO(n)The same adder works for signed and unsigned numbers.
    Extra spacen bits per number

    Quick check

    Test yourself — pick an answer to see if you got it.

    1. What is the 8-bit two's complement representation of −5?

    2. What range of values can an n-bit two's complement number hold?

    3. What weight does the leftmost bit have in an 8-bit two's complement number?

    4. Why do computers prefer two's complement over sign-magnitude?

    Saved only in this browser — no account needed.
    Spotted a mistake or a bug in the 3D model?

    Report a mistake

    in Two's Complement. Thank you — every report makes the lesson better for the next reader.

    We'll also include a link to the step of the 3D model you're on and your browser type, so we can reproduce it.