All subjects · Computer Science · WCP04 Advanced Practical Programming and Problem-solving
Floating-point data and the decimal module
Edexcel IAL Computer Science · WCP04 Advanced Practical Programming and Problem-solving
Floats are stored in binary, so most decimal fractions are approximations. For money and other exact decimal work, Python's `decimal` module gives exact results and full control of rounding.
Why floats go wrong
A float uses binary fractions (halves, quarters, eighths and so on). 0.1 has no exact binary form, just as one third has no exact decimal form, so tiny errors appear and == comparisons can fail. A Decimal stores the decimal digits exactly.
from decimal import Decimal
print(0.1 + 0.2, 0.1 + 0.2 == 0.3)
print(Decimal("0.1") + Decimal("0.2"), Decimal("0.1") + Decimal("0.2") == Decimal("0.3"))
print(Decimal(0.1))Output:
0.30000000000000004 False
0.3 True
0.1000000000000000055511151231257827021181583404541015625Always create a Decimal from a string, such as Decimal("0.1"). Decimal(0.1) copies the float's error exactly, as the last line shows.
Rounding and precision
quantize(Decimal("0.01"))rounds to 2 decimal places. The default rounding mode is ROUND_HALF_EVEN (banker's rounding); passrounding=ROUND_HALF_UPfor the 'school' rule where halves go up.getcontext().precsets the number of significant figures kept in arithmetic results (default 28).
from decimal import Decimal, getcontext, ROUND_HALF_UP
cost = Decimal("2.665")
print(cost.quantize(Decimal("0.01")))
print(cost.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
getcontext().prec = 6
print(Decimal(1) / Decimal(7))Output:
2.66
2.67
0.142857Type conversion and exceptions
Decimal + intworks;Decimal + floatraises TypeError, so convert the float withDecimal(str(x))or keep everything as Decimal.Decimal("twelve")raises decimal.InvalidOperation.- Dividing by
Decimal(0)raises decimal.DivisionByZero, which is a kind of ZeroDivisionError, soexcept ZeroDivisionErrorcatches it. float(d)andstr(d)convert back.
from decimal import Decimal, InvalidOperation
for text in ["12.50", "twelve"]:
try:
print(Decimal(text) * 2)
except InvalidOperation:
print("not a number:", text)
try:
print(Decimal("1.5") + 0.5)
except TypeError:
print("cannot mix Decimal and float")
try:
print(Decimal(1) / Decimal(0))
except ZeroDivisionError:
print("division by zero")Output:
25.00
not a number: twelve
cannot mix Decimal and float
division by zeroComparing values
- Decimals compare by value:
Decimal("2.5") == Decimal("2.50")is True. a.compare(b)returns Decimal -1, 0 or 1 for less than, equal or greater than.copy_abs()gives the absolute value;sqrt()the square root; built-inmax()andmin()work on Decimals.- For floats, never test
==on calculated values: usemath.isclose(a, b)or check thatabs(a - b)is below a small tolerance.
import math
from decimal import Decimal
a, b = Decimal("2.5"), Decimal("2.50")
print(a == b, a.compare(b), Decimal("3").compare(a), Decimal("-4.2").copy_abs())
print(max(Decimal("1.10"), Decimal("1.9")), Decimal("2").sqrt().quantize(Decimal("0.001")))
print(math.isclose(0.1 + 0.2, 0.3))Output:
True 0 1 4.2
1.9 1.414
TrueWhat the PLS lists, and how Python writes it
The PLS decimal list is: Decimal(value), getcontext() and getcontext().prec, sqrt(), compare, copy_abs(), min(), max(), logical_and(), logical_or() and logical_xor(). Points to watch:
- The PLS writes compare as
decimal.compare(x, y), but the decimal module has no function of that name. In Python writex.compare(y), orgetcontext().compare(x, y). quantizeandROUND_HALF_UPare not in the PLS, but they are standard Python and valid in an answer. Within the PLS,round(d, 2)on a Decimal returns a Decimal rounded half to even (round(Decimal("2.665"), 2)gives 2.66), which is not the PLS's '0.5 rule'.logical_and,logical_orandlogical_xorwork digit by digit on Decimals whose digits are all 0 or 1; any other digit raises InvalidOperation.
from decimal import Decimal, getcontext
x, y = Decimal("3.2"), Decimal("5")
print(x.compare(y), getcontext().compare(y, x), round(Decimal("2.665"), 2), round(Decimal("2.675"), 2))
print(Decimal("1100").logical_and(Decimal("1010")), Decimal("1100").logical_or(Decimal("1010")), Decimal("1100").logical_xor(Decimal("1010")))Output:
-1 1 2.66 2.68
1000 1110 110Worked example
A shop sells 3 items at 19.99 and adds 20% VAT. Calculate the total to the nearest penny with halves rounded up.
- ```python from decimal import Decimal, ROUND_HALF_UP PRICE = Decimal("19.99") VAT = Decimal("0.20") total = PRICE * 3 * (1 + VAT) print(total) print(total.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)) ```
- Output: ``` 71.9640 71.96 ```
Answer: Every value is created from a string, so the arithmetic is exact, and quantize applies the required rounding once, at the end.
Check yourself
- What does this program print?
```python
print(0.1 + 0.2 == 0.3, round(0.1 + 0.2, 10) == 0.3)
```
Show answer
False True. 0.1 + 0.2 is stored as 0.30000000000000004, so the first test fails; rounding first removes the tiny error. Output: `False True`
- What does this program print?
```python
from decimal import Decimal, ROUND_HALF_UP
x = Decimal("4.125")
print(x.quantize(Decimal("0.01")), x.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
```
Show answer
4.12 4.13. 4.125 is exactly half way. Half-even goes to the even digit, 4.12; half-up gives 4.13. Output: `4.12 4.13`
- What does this program print?
```python
from decimal import Decimal, getcontext
getcontext().prec = 4
print(Decimal(2) / Decimal(3))
```
Show answer
0.6667. prec = 4 keeps 4 significant figures, rounding the last: `0.6667`
- What does this program print?
```python
from decimal import Decimal
print(Decimal("1.1") * 3, 1.1 * 3)
```
Show answer
3.3 3.3000000000000003. The Decimal result is exact, 3.3. The float result shows binary error. Output: `3.3 3.3000000000000003`
- What does this program print?
```python
from decimal import Decimal
print(Decimal("7.0").compare(Decimal("7.5")))
```
Show answer
-1. 7.0 is less than 7.5, so compare returns `-1`.
- What happens when Python evaluates `Decimal("2.5") + 1.5`?
- It returns Decimal('4.0')
- It returns the float 4.0
- It raises InvalidOperation
- A TypeError is raised
Show answer
A TypeError is raised. Python refuses to mix Decimal and float implicitly, because the float may carry binary error. Write `Decimal("1.5")` instead.
- Which line creates the exact value 0.7 as a Decimal?
- `Decimal(0.7)`
- `Decimal("0.7")`
- `Decimal(7 / 10)`
- `float(Decimal("0.7"))`
Show answer
`Decimal("0.7")`. A string gives the exact decimal digits; the float 0.7 is already an approximation before Decimal sees it.
- A program converts user input with `Decimal(text)`. Which exception should it catch for input such as 'ten'?
- decimal.InvalidOperation
- ValueError only
- ZeroDivisionError
- KeyError
Show answer
decimal.InvalidOperation. Decimal raises InvalidOperation for a string that is not a number. (InvalidOperation also counts as an ArithmeticError.)
Sources
- Pearson Edexcel International Advanced Subsidiary/Advanced Level in Computer Science specification, Issue 1 (March 2026)
- Pearson Edexcel IAL Computer Science Unit 4 Programming Language Subset (PLS)
- Pearson Edexcel IAL Computer Science sample assessment materials (Unit 3 and Unit 4)
Last updated 8 November 2026. Spotted a mistake? Tell us.