Skip to content

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:

warning: comparing floating-point with ‘==’ or ‘!=’ is unsafe [-Wfloat-equal]

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

Open in Compiler Explorer ↗ Quiz this entry