gl/ripetizioni

Two's complement and floating point: the guide

Signed integers in two's complement, overflow and IEEE 754 floating-point numbers: the first TPSIT test in Year 3, with step-by-step worked exercises.

by Gaetano Livornese

Read the original in Italian

It is the end of September 2026, Year 3 at the technical institute (the Italian istituto tecnico), Information Technology and Telecommunications track: TPSIT (the technical subject on the design of computing and telecommunications systems) has opened the year with the first module of the programme, the encoding of information, and has entered — or is about to enter, between the end of September and October — the densest part: base conversions, two’s complement, Boolean algebra. The first written test usually falls five to six weeks from now, so between the end of October and the beginning of November, and it is almost always pure calculation: conversions and numerical exercises to do by hand, with no room to “explain in words” if the sum doesn’t come out.

You have usually already seen base conversions (decimal, binary, hexadecimal) in Year 1; if you need to revise them quickly, the step-by-step method is in binary and hexadecimal in Year 1 at the technical school — here I start from where that post stops and take the conversions for granted. The new thing this year is representing numbers with a sign, and later also non-integer numbers: that is where two’s complement comes from, and that is where floating point arrives.

The problem: how do you represent a negative number in binary?

A byte has no symbol for “minus”. It has only 8 cells that can hold 0 or 1. To represent signed integers you need conventions that decide, among the possible configurations of a byte, which count as positive and which as negative. There are three historical conventions; the first two are useful for understanding why the third is used.

Sign and magnitude: the most intuitive idea, but with a flaw

The most natural idea is to dedicate one bit to the sign (usually the most significant, on the left: 0 for positive, 1 for negative) and the remaining bits to the absolute value. On 4 bits, is written and is written . The flaw shows up at once with zero: and are two different configurations for the same number, so on bits only distinct useful values remain, not . Also, adding two numbers like this doesn’t work with direct binary addition: you first have to check the signs and then decide whether to add or subtract the magnitudes — for a simple, cheap circuit, that is a problem.

One’s complement: a step forward, not yet the solution

The one’s complement of a number is obtained by inverting every bit. On 4 bits, and its one’s complement is . Addition works again with the usual binary logic, but the double-zero problem remains: and its one’s complement is , still read as "". Two distinct zeros, again one fewer representable value than possible.

Two’s complement: the convention actually used

Two’s complement solves the problem in one go: you take the one’s complement and add 1 to it. On 4 bits, the two’s complement of is: invert → , add 1 → , which, discarding the excess carry (you always stay within bits), goes back to . A single zero, and negative zero simply no longer exists as a configuration of its own.

There are two equivalent ways to obtain or read a number in two’s complement, and both are needed: the first to build a representation from a decimal number, the second to read one quickly in a test without redoing all the steps.

Method 1 — invert and add 1. To represent on bits: write in binary on bits, invert every bit, add 1 to the result.

Method 2 — negative weight of the most significant bit. To read the value of a number already written in two’s complement, the leftmost bit (the most significant) is not worth as in unsigned integers: it is worth . All the other bits keep their usual positive weight:

The two methods must always give the same result: one builds the representation, the other checks it. The first worked exercise below uses both on the same number.

The representable range on n bits

With bits in two’s complement you represent values, distributed asymmetrically between negatives and positives:

On 8 bits: from to . The asymmetry (one extra negative) is a direct consequence of having a single zero: zero counts as non-negative, so the positive side has one value fewer than it would otherwise have.

Addition and subtraction: always the same binary addition

The practical advantage of two’s complement is that subtraction is not needed as an operation of its own: is calculated as , where is the two’s complement of , and you add with ordinary column binary addition — no sign checks, no special logic.

An example: on 8 bits becomes . I write , complement it: invert → , add 1 → (this is ). I add:

  0 0 1 1 0 0 1 0    (50)
+ 1 0 1 1 1 0 1 0    (-70)
-------------------
  1 1 1 0 1 1 0 0

Here no carry comes out of the leftmost bit; if there were one, it would be discarded (you always stay on 8 bits). I read the result with the negative-weight method: . Correct: .

Overflow: it is not the same as carry

The carry is the one that comes out of the most significant bit during an addition. Overflow, in two’s complement, is a different concept: it means that the result of an operation between two signed numbers does not fall within the range , even though formally the binary addition “works” perfectly.

The practical rule for recognising it: overflow can only happen when adding two numbers of the same sign, and it shows up as a result with the wrong sign. When you add a positive and a negative, the result is always representable and overflow cannot occur — that is the case of just seen: there was a discarded carry, but no overflow. The second exercise below shows the case where overflow really occurs.

Sign extension

When a number in two’s complement has to be moved into a wider register (from 8 to 16 bits, for example), it is not enough to add zeros on the left as you would for an unsigned number: you have to repeat the sign bit in all the new positions. A negative number on 4 bits, , extended to 8 bits becomes , not (which would be worth , a completely different number). Repeating the sign 1 keeps the value unchanged; repeating zeros would destroy it.

IEEE 754 floating point, single precision

Two’s complement represents integers. For non-integer numbers — with a fractional part — the almost universal standard is IEEE 754, and in the single-precision version it uses 32 bits divided into three fields:

FieldBitsRole
Sign (S)10 = positive, 1 = negative
Exponent (E)8stored with bias 127: real value =
Mantissa (M)23digits after the point in the normalised form, without the implicit bit

The bias avoids representing the exponent with a separate sign: you always add 127 before writing it, and subtract it to read it. The mantissa exploits a fact of binary normalisation: a non-zero number, in scientific notation in base 2, always has the form — the bit before the point is always 1, so there is no need to store it. This is the implicit bit: a free bit of precision, because you never write it but always consider it present when reading.

How to convert a decimal number

The procedure for converting a decimal number into IEEE 754 single precision always has the same steps:

  1. Convert the integer part and the fractional part separately into binary.
  2. Write the number as (normalisation: you shift the point until only one 1 remains before it).
  3. The exponent to store is , written in binary on 8 bits (unsigned: the bias has already absorbed the negative).
  4. The mantissa to store is the digits after the point of the normalised form, padded with zeros up to 23 bits.
  5. The sign bit is 0 or 1 depending on the sign of the original number.

The third worked exercise below applies these five steps in full to .

Why 0.1 is never exact in floating point

Not all decimal numbers have a finite binary representation, and is the most cited example. Converting it with successive multiplications by 2 gives a sequence that never ends:

with the block repeating for ever, like in base 10. The mantissa has only 23 bits: that sequence has to be cut and rounded, so the stored value is the closest possible to 0.1, not exactly 0.1. That is why, and not because of a bug in the language, 0.1 + 0.2 prints almost everywhere 0.30000000000000004 instead of 0.3: both addends are already approximated before being added.

Three worked exercises

1. Representing on 8 bits in two’s complement

I write in binary on 8 bits: .

I invert every bit (one’s complement): .

I add 1: .

So on 8 bits in two’s complement is . I check with the negative-weight method, without redoing the steps from scratch: the leftmost bit is worth , the others have normal positive weight.

It checks out: .

2. Addition with overflow on 8 bits

I add and , both positive, on 8 bits: , .

  0 1 1 0 0 1 0 0    (100)
+ 0 0 1 1 0 0 1 0    (50)
-------------------
  1 0 0 1 0 1 1 0

The binary result is . Read as a signed number (leftmost bit , so negative): . But in normal arithmetic, and exceeds the maximum representable on 8 signed bits (): it is overflow. The signal that gives it away, besides the fact that : I added two positive numbers and got a result that reads as negative — by the rule seen above, this can only happen in the presence of overflow, never in a correct addition.

3. in IEEE 754 single precision, in hexadecimal

Integer part ; fractional part (because ). So .

I normalise: .

  • Sign: (the number is negative).
  • Exponent: .
  • Mantissa: the digits after the normalised point, , padded to 23 bits with zeros: .

The full 32 bits, sign-exponent-mantissa:

I group them into 4-bit nibbles to read them in hexadecimal: , that is .

An honest note: our practice tests for school cover maths and physics, not yet computer science. If in Year 3 you are also worried about maths, there you will find a practice test per topic: the correct answer to each question is free, the guided solution unlocks with your first lesson.

Typical mistakes

  • Forgetting to discard the excess carry after adding 1 in the two’s complement of , or in general after an addition that produces a carry beyond the bits available: you always stay within the given number of bits.
  • Confusing carry and overflow. A carry out of the most significant bit is not in itself overflow (see the example above, where there is a carry but no overflow): overflow is checked on the sign of the result relative to the signs of the operands, not on the carry.
  • Extending the sign with zeros instead of repeating the most significant bit, which on a negative number completely changes the value.
  • Forgetting the implicit bit in the IEEE 754 mantissa, either by writing it explicitly by mistake or by forgetting it when reading, when converting a number back from hexadecimal to decimal.
  • Rounding the biased exponent badly: the stored exponent is always , never on its own — a sign error here moves the number by enormous powers of two.

Where it comes back later

Two’s complement doesn’t stay confined to this module: it is how a real CPU — the one whose diagram you saw in Von Neumann architecture and the CPU — represents integers in memory and in the ALU.

The circuits that carry out these binary additions are made of logic gates, which I discuss in logic gates and Karnaugh maps.

The rest of the computing programme, loops and arrays included, is covered in nested loops and arrays in Year 3 computing; the full picture of the subject is on the computer science page. If you want a hand preparing for the end-of-October test, start with a free introductory call: half an hour to understand where to concentrate the last revision.

Keep reading

Want to put what you read into practice?

Let's talk for 30 minutes, free: we look together at where you are stuck and I tell you honestly how I can help.

Or message me on WhatsApp.