Vấn đề này liên quan đến cách mà máy tính lưu trữ và xử lý số thực (floating-point numbers). Trong nhiều ngôn ngữ lập trình, số thực được lưu trữ theo chuẩn IEEE 754, và không phải tất cả các số thực đều có thể được biểu diễn chính xác trong hệ nhị phân. Do đó, khi thực hiện các phép toán như 0.1 + 0.2, kết quả có thể không chính xác như mong đợi.
Một số chỉ có thể biểu diễn chính xác trong IEEE-754 nếu và chỉ nếu nó có thể viết dưới dạng: x = k / (2^n) với k và n là số nguyên. Nói cách khác, mẫu số của số đó chỉ có thể chứa các thừa số nguyên tố 2 (không có 3, 5, 7, ...).
Ví dụ:
- Chính xác: 0.5 = 1/2, 0.25 = 1/4, 0.75 = 3/4
- Không chính xác: 0.1 = 1/10, vì 10 = 2 × 5 → có số 5 → không biểu diễn chính xác.
- Không chính xác: 0.2 = 1/5, vì có số 5 → cũng không chính xác.
| Decimal | Binary (approx) | Stored value (approx) |
|---|---|---|
| 0.1 | 0.00011001100110011001100110011001100110011001100110011010... | 0.10000000000000000555 |
| 0.2 | 0.00110011001100110011001100110011001100110011001100110100... | 0.20000000000000001110 |
| 0.3 | 0.01001100110011001100110011001100110011001100110011001100... | 0.29999999999999998890 |
| 0.1+0.2 | 0.01001100110011001100110011001100110011001100110011010000... | 0.30000000000000004440 |
So sánh kết quả Binary (approx) thấy rằng 5 bit cuối cùng khác nhau ở bảng trên (được bôi đậm). Do đó, 0.1 + 0.2 không bằng 0.3. Kết quả là FALSE.
| Decimal | Binary (approx) | Stored value (approx) |
|---|---|---|
| 0.1 | 0.00011001100110011001100110011001100110011001100110011010... | 0.10000000000000000555 |
| 0.1 | 0.00011001100110011001100110011001100110011001100110011010... | 0.10000000000000000555 |
| 0.2 | 0.00110011001100110011001100110011001100110011001100110000... | 0.20000000000000001110 |
| 0.1+0.1 | 0.00110011001100110011001100110011001100110011001100110000... | 0.20000000000000001110 |
So sánh kết quả Binary (approx) như nhau. Do đó, 0.1 + 0.1 bằng 0.2. Kết quả là TRUE.
| Decimal | Binary (approx) | Stored value (approx) |
|---|---|---|
| 0.1 | 0.00011001100110011001100110011001100110011001100110011010... | 0.10000000000000000555 |
| 0.25 | 0.01 | 0.25 |
| 0.35 | 0.01011001100110011001100110011001100110011001100110011000... | 0.34999999999999997780 |
| 0.1+0.25 | 0.01011001100110011001100110011001100110011001100110011000... | 0.34999999999999997780 |
So sánh kết quả Binary (approx) như nhau. Do đó, 0.1 + 0.25 bằng 0.35. Kết quả là TRUE.
Cần cẩn trọng khi so sánh các số thực, đặc biệt là khi chúng được tạo ra từ các phép toán.
Khi cần so sánh, hãy sử dụng một ngưỡng (epsilon) để kiểm tra sự gần đúng thay vì so sánh trực tiếp.
Ví dụ với Python (các ngôn ngữ khác sẽ có các cách giải quyết tương đương):
epsilon = 1e-10
if abs((0.1 + 0.2) - 0.3) < epsilon:
print("0.1 + 0.2 gần bằng 0.3")
else:
print("0.1 + 0.2 không gần bằng 0.3")hoặc sử dụng phương thức math.isclose() được giới thiệu trong Python 3.5 với PEP 458:
import math
if math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-10):
print("0.1 + 0.2 gần bằng 0.3")
else:
print("0.1 + 0.2 không gần bằng 0.3")