Normalisation of floating-point numbers
The same number can be written in floating point in many ways, just as , and are all 500. Normalisation picks one standard form: the one that wastes no mantissa bits. Paper 3 asks you to recognise whether a number is normalised, to normalise it by shifting the mantissa and adjusting the exponent, and to explain why normalisation is done. It builds directly on floating-point numbers.
Many representations of one number
With an 8-bit mantissa and a 4-bit exponent, can be stored as:
| Mantissa | Exponent | Value |
|---|---|---|
01000000 | 1111 () | |
00100000 | 0000 () | |
00010000 | 0001 () | |
00001000 | 0010 () |
Every row is correct, but only the first uses the mantissa well. In the others, the 0s after the sign bit are just copies of the sign; they store no information and take up places that could hold significant bits.
What a normalised number looks like
A floating-point number is normalised when the first two bits of the mantissa are different:
- a positive normalised mantissa starts
01 - a negative normalised mantissa starts
10
Put in terms of value, a normalised mantissa satisfies if positive and if negative.
A mantissa starting 00 or 11 is not normalised: the second bit merely repeats the sign.
The negative case catches people out. 11010000 is not normalised, even though it has a 1 in the second place; the second bit copies the sign bit. Normalised negatives begin 10.
Why numbers are normalised
Normalisation:
- Maximises precision. Redundant leading sign bits are removed, so the mantissa holds as many significant bits as possible for its length.
- Gives a unique representation of each number, so two stored values can be compared directly and there is no ambiguity.
- Makes arithmetic simpler and more consistent, because every operand is in the same form.
Precision is the reason that matters most. Suppose a calculation produces and there is an 8-bit mantissa. Without normalising, the mantissa can only hold 0.0001011, keeping four significant bits (1011) and losing the final 011. Normalised as , the mantissa 01011011 keeps all seven significant bits.
How to normalise
The rule is a single trade: moving the mantissa one place left doubles it, so the exponent must go down by 1 to keep the value the same.
- Look at the first two bits of the mantissa. If they differ (
01or10), it is already normalised. - Otherwise, shift all mantissa bits left one place, putting a 0 in the rightmost place.
- Subtract 1 from the exponent for every place shifted.
- Repeat until the first two bits differ. (A positive number ends up starting
01, a negative one10. The sign bit never changes, because every bit shifted out is just a copy of it.) - Write the new exponent in two's complement, and check it still fits in the exponent's width. If it does not, the number cannot be normalised in this format.
- Check that the value is unchanged.
A shortcut: count how many places the first 01 or 10 pattern is from the start, shift by that many places at once, and subtract that number from the exponent.
A floating-point number has an 8-bit mantissa 00011010 and a 4-bit exponent 0101, both in two's complement. Normalise it.
Solution
The mantissa starts 00, so it is not normalised. The first 1 is in the fourth place, so the mantissa must move 2 places left to start 01.
Mantissa: 00011010 → 01101000.
Exponent: → 0011.
| Mantissa | Exponent |
|---|---|
01101000 | 0011 |
Check: before, . After, .
Normalise the floating-point number with mantissa 11100110 and exponent 0010.
Solution
The mantissa starts 11, so it is not normalised. Shifting left: 11100110 → 11001100 (still 11) → 10011000 (now 10). That is 2 places.
Exponent: → 0000.
| Mantissa | Exponent |
|---|---|
10011000 | 0000 |
Check: before, . After, .
Normalise mantissa 00001100, exponent 0001 (8-bit mantissa, 4-bit exponent).
Solution
The mantissa needs to move left until it starts 01: 00001100 → 01100000 is a shift of 3 places.
Exponent: . In 4-bit two's complement: , invert to 1101, add 1 → 1110.
| Mantissa | Exponent |
|---|---|
01100000 | 1110 |
Check: before, . After, .
A number is stored with a 10-bit mantissa 1111001100 and a 6-bit exponent 111110, both in two's complement.
(a) Explain why the number is not normalised. (b) Normalise it. (c) Convert the normalised number to denary.
Solution
(a) The first two bits of the mantissa are both 1. A normalised negative mantissa must start 10, so the second bit is a redundant copy of the sign and precision is being wasted.
(b) 1111001100 → 1110011000 → 1100110000 → 1001100000: 3 places left.
Exponent: 111110 ; . , invert 111010, add 1 → 111011.
| Mantissa | Exponent |
|---|---|
1001100000 | 111011 |
(c) Mantissa 1.001100000 . Value .
Check against the original: .
An 8-bit mantissa and 4-bit exponent hold mantissa 00000011 and exponent 1001. Explain why this cannot be normalised in this format.
Solution
The exponent 1001 is . To start 01 the mantissa must move left 5 places (00000011 → 01100000), so the exponent would need to become .
A 4-bit two's complement exponent can only go down to , so cannot be stored. The number is too small to be represented in normalised form in this format: this is underflow. The system would store it as 0 (or keep it unnormalised, losing precision), so the true value is lost.
Zero and the special cases
- Zero cannot be normalised: the mantissa
00000000will never start01, however far it is shifted. Systems treat a zero mantissa as a special case meaning 0. - is stored as mantissa
10000000, which starts10, so it is already normalised. - looks as though it should be
11000000with exponent 0, but that starts11. Normalised, it is10000000(that is, ) with exponent1111(): . The asymmetry exists because two's complement can hold but not .
Normalising in Python
def twos(bits):
v = int(bits, 2)
return v - (1 << len(bits)) if bits[0] == "1" else v
def to_bits(value, width):
if not -(1 << (width - 1)) <= value < (1 << (width - 1)):
raise OverflowError(f"{value} does not fit in {width} bits")
return format(value & ((1 << width) - 1), f"0{width}b")
def normalise(mantissa, exponent):
if set(mantissa) == {"0"}:
return mantissa, exponent # zero is a special case
exp = twos(exponent)
while mantissa[0] == mantissa[1]: # first two bits the same
mantissa = mantissa[1:] + "0" # shift left
exp -= 1 # compensate
return mantissa, to_bits(exp, len(exponent))
print(normalise("00011010", "0101")) # ('01101000', '0011')
print(normalise("11100110", "0010")) # ('10011000', '0000')
print(normalise("00001100", "0001")) # ('01100000', '1110')
print(normalise("1111001100", "111110")) # ('1001100000', '111011')
try:
print(normalise("00000011", "1001"))
except OverflowError as error:
print("Cannot normalise:", error) # -12 does not fit in 4 bits
- Shifting the mantissa left makes it bigger, so the exponent goes down. Students often add instead of subtract.
- Do not change the sign bit by hand. Shifting a negative mantissa left keeps the leading 1 automatically because the bits being shifted out are all 1s.
- Fill vacated places on the right with 0.
- Recalculate the exponent in two's complement; do not just change one bit.
- "Explain why floating-point numbers are normalised" earns marks for: maximum precision for a given number of bits (no redundant leading bits), a unique representation of each number, and easier comparison/arithmetic.
- "State how you know this number is normalised" needs both cases: positive starts
01, negative starts10. - For a "normalise this" question, show the shifted mantissa, the number of places, and the exponent calculation in denary before converting to binary.
- If a question gives a mantissa and asks for the "normalised" form of a denary number, your answer must start
01or10, or it scores nothing.
- A normalised mantissa has first two bits different: positive
01, negative10. - Normalisation maximises precision and gives a unique representation of every number.
- To normalise: shift the mantissa left until the first two bits differ, subtracting 1 from the exponent per place.
- Check the new exponent still fits; if it does not, the number cannot be represented normalised (underflow).
- Zero cannot be normalised; normalises to mantissa with exponent .
Practice questions
- State, with a reason, which of these 8-bit mantissas are normalised:
01011000,00110000,10111000,11010000. - Normalise mantissa
00101100, exponent0110(8-bit and 4-bit two's complement), and give the denary value. - Normalise mantissa
11110100, exponent0011, and show that the value is unchanged. - Normalise mantissa
11101000, exponent1110. - Normalise the number with 10-bit mantissa
0001011010and 6-bit exponent000111, and convert the result to denary. - Give two reasons why floating-point numbers are stored in normalised form.
- Explain why mantissa
00110000with exponent1000cannot be normalised in an 8-bit mantissa, 4-bit exponent format. - Show how is stored as a normalised floating-point number with an 8-bit mantissa and a 4-bit exponent, and explain why
11000000with exponent0000is not acceptable. - A computer stores the result of a calculation as in a system with an 8-bit mantissa and 4-bit exponent. Show the stored value if it is (a) stored without normalising, keeping the exponent as 3, (b) normalised. Give the denary value of each and state the error in each case.
Answers
-
01011000: normalised (positive, starts01).00110000: not normalised (starts00).10111000: normalised (negative, starts10).11010000: not normalised (starts11, second bit copies the sign). -
Shift 1 place:
01011000. Exponent →0101. Value . -
11110100→11101000→11010000→10100000: 3 places. Exponent →0000. Before: . After: . Unchanged. -
11101000→11010000→10100000: 2 places. Exponent1110; →1100. Mantissa10100000, exponent1100. Value . -
0001011010→0101101000: 2 places. Exponent →000101. Value . -
Any two of: it gives the maximum precision for the number of bits, because no mantissa bits are wasted on redundant leading 0s or 1s; each number has exactly one representation; it makes comparison and arithmetic of floating-point values consistent and simpler.
-
The exponent
1000is , the most negative value a 4-bit exponent can hold. Normalising needs one left shift (00110000→01100000), which would make the exponent , and that cannot be stored. The value is , which is smaller than the smallest positive normalised number in this format, . It is too small to be normalised: underflow. -
Mantissa
10000000(), exponent1111(): .11000000with exponent 0 has the value but starts11, so it is not normalised: the second bit is a redundant copy of the sign, and one bit of precision is wasted. -
The true value is .
(a) Unnormalised, the 8-bit mantissa holds only
0.0000101, so the stored value is . Error .(b) Normalised: , mantissa
01011010, exponent1111. Stored value . Error . All the significant bits fit once the leading zeros are removed.