Why 0.1 + 0.2 ≠ 0.3 in Programming
🎯 The Question
"Why does executing
0.1 + 0.2 == 0.3evaluate tofalsein Python, JavaScript, Java, and C++ (resulting in0.30000000000000004)? Why is using floating-point types strictly forbidden in financial and banking software?"
⚡ 30-Second Elevator Pitch
Computers do not store numbers in decimal (Base 10); they store them in binary (Base 2) using the IEEE 754 Floating-Point Standard.
- In decimal, a fraction can only be represented cleanly with finite digits if its denominator has prime factors of only 2 and 5 (like or ). Factions like repeat infinitely.
- In binary, a fraction can only be finite if its denominator is a pure power of 2.
- Because the decimal number 0.1 is (which contains factor 5), in binary it becomes an infinitely repeating fraction:
Because standard 64-bit double-precision floats have only a 53-bit mantissa (significand), the infinite stream is truncated and rounded, yielding:
🧠 Under-the-Hood: Binary Mantissa Truncation
🔬 How Fintech & Banking Architectures Handle Money
In banking and e-commerce platforms, storing money in float or double is an instant bug that causes balances to drift over time.
Production solutions enforce two patterns:
- Integer Minor Units (Cents / Paise): Store all amounts as integers representing the smallest currency unit:
- Instead of storing
$10.50asfloat 10.50, store1050cents as a 64-bit integer (BIGINT).
- Instead of storing
- Arbitrary-Precision Decimal Types:
- Java:
BigDecimal - Python:
decimal.Decimal - SQL:
DECIMAL(19, 4)/NUMERIC
- Java:
📌 Comparison Matrix: Floating-Point vs. Fixed-Point / Integer
| Dimension | float / double (IEEE 754) | BigDecimal / DECIMAL(18,2) | Integer Minor Units (Cents / Paise) |
|---|---|---|---|
| Precision | Inexact / Approximate | Exact decimal precision | Exact integer precision |
| CPU Execution | ⚡ Blazing fast (Direct FPU hardware) | 🐢 Slower (Software-emulated math) | ⚡ Blazing fast (Standard integer ALU) |
| Memory Footprint | 4 to 8 bytes | Heavy heap object allocations | 8 bytes (int64_t / BIGINT) |
| Rounding Errors | Inevitable on decimal fractions | Fully controlled rounding modes | Zero fractional rounding drift |
| Use Cases | 3D graphics, physics simulations, ML | Core accounting, tax engines | Stripe, PayPal, billing APIs |
💡 What Interviewers Ask Next (Follow-Up Traps)
-
"How should you safely compare two floating-point numbers in code?"
- Answer: Never use strict equality (
a == b). Compare using an epsilon tolerance window:# Safe floating-point equality check
def is_equal(a, b, epsilon=1e-9):
return abs(a - b) < epsilon
- Answer: Never use strict equality (
-
"What is Bankers' Rounding (Half-Even Rounding), and why do financial systems mandate it?"
- Answer: Standard elementary rounding (round half up) creates an upward statistical bias over millions of transactions. Bankers' Rounding rounds
.5to the nearest even number (e.g.2.5 -> 2and3.5 -> 4). This ensures that over massive datasets, rounding errors cancel each other out symmetrically.
- Answer: Standard elementary rounding (round half up) creates an upward statistical bias over millions of transactions. Bankers' Rounding rounds
Interview Answer: 0.1 + 0.2 != 0.3 because computers store numbers in binary floating-point (IEEE 754). The fraction is an infinitely repeating fraction in binary, just as is in decimal. Truncating to the 53-bit mantissa introduces tiny precision errors. Financial systems avoid floats by using integer minor units (cents) or arbitrary-precision BigDecimal.