Floating-point number pitfalls in programming

Floating-point numbers are one of the concepts that every developer encounters early on. They allow decimal numbers to be represented in almost every programming language. However, their behavior can be surprising and cause difficult-to-understand bugs, especially when you are just starting to learn programming.
A classic example:
print(0.1 + 0.2)Result:
0.30000000000000004At first glance, this can be surprising and may look like a language error. However, this behavior is normal and comes from the way computers store floating-point numbers.
Computers do not store numbers like we do
We are used to using the decimal system, with digits after the decimal point. Computers, on the other hand, work with the binary system.
Some numbers are easy to represent in binary:
0.5 = 0.1 in binary
0.25 = 0.01 in binaryBut other simple numbers in base 10 cannot be represented exactly in base 2.
For example, 0.1 has an infinite binary representation:
0.1 = 0.00011001100110011...Since computers have limited memory, they must store an approximation of this value.
The IEEE 754 standard
Most programming languages use the IEEE 754 standard to represent floating-point numbers.
A floating-point number is generally composed of three parts:
- the sign (positive or negative);
- the exponent;
- the mantissa (or significand).
For a double-precision (double) number, the standard generally uses 64 bits:
- 1 bit for the sign;
- 11 bits for the exponent;
- 52 bits for the mantissa.
This representation makes it possible to store very large or very small numbers, but with limited precision.
Rounding errors
Because of these approximations, mathematical operations can produce small differences.
Let's use the previous example again:
print(0.1 + 0.2)Result:
0.30000000000000004These differences are usually invisible to users, but they can become problematic in certain fields.
Never directly compare floating-point numbers
A common mistake is comparing two floating-point numbers using strict equality.
Bad example:
if result == 0.3:
print("OK")This comparison can fail because of precision errors.
A better approach is to use a tolerance value (epsilon):
if abs(result - 0.3) < 0.000001:
print("OK")This method checks that the two values are close enough.
Some languages also provide dedicated functions:
Python:
import math
math.isclose(0.1 + 0.2, 0.3)Problems with money
Floating-point numbers are often not suitable for representing monetary values.
Let's take a simple example:
price = 0.1
quantity = 3
print(price * quantity)
The result may contain a small rounding error.
For financial calculations, this difference can become significant after multiple operations.
It is better to use a decimal type when precision is essential. Python's Decimal type uses a decimal representation with controlled precision, which helps avoid errors related to the binary representation of float values.
In Python:
from decimal import Decimal
price = Decimal("0.1")
quantity = 3
print(price * quantity)Result:
0.3Databases also often provide suitable types such as DECIMAL or NUMERIC.
When should you use floating-point numbers?
Floating-point numbers remain essential in many fields:
- scientific computing;
- artificial intelligence;
- image processing;
- video games;
- physics simulations;
- statistics.
In these cases, a small rounding error is often acceptable in exchange for performance and the available range of values.
When should you use decimal numbers?
Decimal numbers are preferable when every digit matters:
- payments;
- accounting;
- invoicing;
- price management;
- financial calculations.
A simple rule:
- use
floatfor scientific calculations and approximate measurements; - use
decimalor integers representing minimal units (for example, cents) for money.
Conclusion
Floating-point numbers are not broken. They work exactly as expected, but their internal representation is different from the way we think about numbers.
Understanding how IEEE 754 works, rounding errors, and precision limitations helps prevent many difficult-to-diagnose bugs.
Despite my many years as a developer, I still sometimes make mistakes and take shortcuts...



Laisser un commentaire