Why 0.3 Is Not Exactly 0.3: Understanding Floating-Point Precision in Programming

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:

DecimalScale ×100Stored Integer
0.33030
1.25125125
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

FeatureBinary FloatFixed-Point / Decimal
Storage base210
Exact 0.1 or 0.3?Not PossiblePossible
Arithmetic errorsPossibleNone (within scale)
SpeedFastSlower

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.