02 Beginner The Hundred
0.1 + 0.2 Is Not 0.3
two receipts, identical numbers on screen, different verdicts
#include <iostream>
void ring_up(const char* item, double a, double b, double price) {
double paid = a + b;
std::cout << item << ": paid " << paid << ", price " << price << " -> "
<< (paid == price ? "exact change" : "wrong amount") << "\n";
}
int main() {
ring_up("coffee", 0.10, 0.20, 0.30);
ring_up("muffin", 0.25, 0.25, 0.50);
}
Run it. Both customers paid exactly the sticker price — do both get through?
Answer
coffee: paid 0.3, price 0.3 -> wrong amount, then muffin: paid 0.5, price 0.5 -> exact
change. The coffee line prints the same number twice, then denies they are equal.
Why¶
Binary floating point represents only fractions that are sums of negative powers of two,
and 0.1 and 0.2 are not — each literal is rounded to the nearest double. Their sum lands
on 0.30000000000000004 while the literal 0.3 rounds down to 0.29999999999999999:
different bits, so == is false. std::cout hides the evidence by showing 6 significant
digits by default — crank it up and the gap appears:
std::cout << std::setprecision(17) << 0.1 + 0.2 << ' ' << 0.3;
// 0.30000000000000004 0.29999999999999999
The muffin passes because 0.25 and 0.5 are exact — negative powers of two survive the
round trip perfectly — which is why a few float comparisons work and lull you into trusting
the rest. Not the optimizer's doing, either: the verdicts are identical under -O0, -O2
and even -Ofast. -Wall -Wextra stays silent; the flag that catches it must be named:
The fix¶
Compare against a tolerance — and for money, drop floating point entirely and count cents:
if (std::abs(paid - price) < 1e-9) // <cmath>: "close enough", not "equal"
long paid = 10 + 20, price = 30; // cents
if (paid == price) // exact, every time
Takeaway: == on floating point asks for bit-exact equality, which arithmetic rarely
gives you — compare with a tolerance, and never bill anyone in double.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo