Great work!

XP to next level

BugEater

How Computers Store Fractions

Learning Objectives

By the end of this lesson you will be able to:

  • Explain in simple terms why 0.1 cannot be stored exactly in binary
  • Describe the IEEE 754 double precision format (64-bit float)
  • Predict which types of calculations are most vulnerable to floating-point error

The Binary Fraction Problem

Humans count in base 10 (decimal). Computers count in base 2 (binary).

In decimal, 1/3 = 0.333... — an infinite repeating decimal. We accept this and round when needed.

In binary, 1/10 (0.1) = 0.000110011001100... — an infinite repeating binary fraction. The computer must round this to fit in the available bits, storing an approximation: approximately 0.1000000000000000055511151231257827021181583404541015625.

This is not a bug. It's the mathematical reality of representing base-10 fractions in base-2.

IEEE 754 Double Precision

A 64-bit floating-point number (Java double, JavaScript number) has:

  • 1 sign bit
  • 11 exponent bits (range: roughly 10^-308 to 10^308)
  • 52 mantissa bits (~15-17 significant decimal digits of precision)

The consequence: any calculation involving fractions may accumulate tiny rounding errors.

The Famous Example

0.1 + 0.2 = 0.30000000000000004
0.1 + 0.2 === 0.3  // false in JavaScript, Python, Java...

This is not a bug in the specific language. It reproduces in every IEEE 754 language because they all use the same binary representation.

When Floating-Point Error Matters

For most applications, the error (about 10^-17 for this example) is negligibly small. But it matters when:

  1. Financial calculations: Accumulating floating-point errors over thousands of transactions compounds into visible penny discrepancies
  2. Equality checks: if (price == 0.10) will fail if price was computed (not assigned) as 0.1
  3. Sorting/comparison: Items that should sort equal may sort differently due to accumulated error
  4. Rounding at scale: Rounding 0.30000000000000004 is different from rounding 0.3

The Correct Approach

  • For money: Use integer arithmetic (store cents as integers, not dollars as floats) or BigDecimal
  • For comparisons: Use epsilon comparison: Math.abs(a - b) < 0.000001 rather than a == b
  • For display: Round to the appropriate number of decimal places before showing to users

Pro Tip: If a financial system shows you a price like $15.999999999997 instead of $16.00, that's almost certainly accumulated floating-point error. It's a bug worth filing — the system should use appropriate numeric types.

Key Takeaways

  • 0.1 cannot be stored exactly in binary IEEE 754 — it's stored as an approximation
  • This affects all IEEE 754 languages: Java, Python, JavaScript, C#, Go, etc.
  • Floating-point errors matter most in financial calculations, equality comparisons, and accumulated operations
  • Use integer arithmetic or BigDecimal for money; epsilon comparison instead of exact equality

Quiz

Why can computers represent 0.5 exactly in binary, but not 0.1?

In Java, what does System.out.println(0.1 + 0.2) print?

A financial application stores prices as Java double. What risk does this introduce?

Which statement about IEEE 754 double precision is TRUE?