If you’ve ever written code like this:
double x = 0.1 + 0.2;
if (x == 0.3) {
printf("Equal\n");
} else {
printf("Not Equal\n"); // This usually prints
}
…and wondered why the “obvious” answer fails? Welcome to the fascinating (and sometimes infuriating) world of floating-point numbers.
The Invisible Problem
At first glance, 0.1 + 0.2 should be 0.3. Simple, right? But computers don’t store decimal numbers in base 10—they store them in binary, as a sequence of 0s and 1s.
Decimal numbers like 0.1, 0.2, and 0.3 often have no exact binary representation. They become repeating fractions in base 2:
0.3 in binary ≈ 0.010011001100110011001100110011…
A computer with finite memory can’t store this infinite pattern. It truncates it, storing a value that’s extremely close but not exactly 0.3.
How 0.3 Is Actually Stored
Most programming languages use the IEEE 754 double-precision format, which has:
- 1 bit for sign
- 11 bits for exponent
- 52 bits for mantissa (the significant digits)
The closest 64-bit representation of 0.3 is:
0.299999999999999988897769753748434595763683319091796875
Printed with limited precision, it appears as:
0.29999999
This explains why 0.1 + 0.2 == 0.3 evaluates to false: the tiny difference exists in memory, even if your eyes don’t see it.
Why This Matters
Floating-point precision isn’t just a curiosity—it’s critical in financial, scientific, and engineering applications. Small rounding errors can compound in calculations, leading to bugs, incorrect results, or even catastrophic failures in high-stakes systems.
How to Avoid Floating-Point Pitfalls
Luckily, there are ways to handle numbers exactly.
1. Fixed-Point Integers
Instead of storing fractions, store scaled integers:
| Decimal | Scale ×100 | Stored Integer |
|---|---|---|
| 0.3 | 30 | 30 |
| 1.25 | 125 | 125 |
Now all arithmetic is done with integers, which are exact:
int amount = 30; // represents 0.30
int price = 125; // represents 1.25
int total = amount + price; // 155 → 1.55 when divided by 100
printf("%.2f\n", total / 100.0);
This is perfect for monetary calculations. The catch however is you must decide your scale upfront.
2. Decimal Types
Languages and databases often provide decimal types that store numbers in base 10:
Java: BigDecimal
SQL: DECIMAL(p, s)
Exact decimal arithmetic, no surprises here. But slightly slower than binary floats, but accuracy matters more than speed in financial applications.
Quick Comparison
| Feature | Binary Float | Fixed-Point / Decimal |
|---|---|---|
| Storage base | 2 | 10 |
| Exact 0.1 or 0.3? | Not Possible | Possible |
| Arithmetic errors | Possible | None (within scale) |
| Speed | Fast | Slower |
The Takeaway
Floating-point numbers are powerful and efficient—but they’re approximations. For most everyday calculations, that’s fine. But when you need perfect accuracy, reach for fixed-point integers or decimal types.