Skip to content
Joey Wang
Menu

Search

Full Stack Development

Floating-Point Precision in Ruby: Why 0.1 + 0.33 ≠ 0.43

Ruby's 0.1 + 0.33 does not equal 0.43 because of binary floating-point rounding, and Rational, BigDecimal, and tolerance comparisons each fix it differently.

· 1 min read

engineering #ruby#debugging#math

Audio summary

0.1 + 0.33 == 0.43 returns false in Ruby. Not a bug: it’s what IEEE 754 floating-point does to decimal fractions that don’t have exact binary representations.

sum = 0.1 + 0.33
puts sum == 0.43  # false

Why the binary representation breaks

Floating-point numbers store real numbers in binary, as defined by IEEE 754. Most decimal fractions don’t map onto binary exactly, the same way 1/3 has no exact decimal representation. 0.1 in binary is 0.00011001100110011..., an infinitely repeating pattern that gets truncated to fit the available bits. Add two truncated approximations together and the rounding error shows up in the result.

This matters most where an exact decimal answer is the requirement: money, quantities, anything that gets compared with == downstream.

Three ways around it

Rational numbers

require 'rational'

rational_sum = Rational(1, 10) + Rational(33, 100)
puts rational_sum        # (43/100)
puts rational_sum.to_f   # 0.43

Rational stores the fraction exactly, no binary approximation involved.

BigDecimal for money

require 'bigdecimal'

big_decimal_sum = BigDecimal("0.1") + BigDecimal("0.33")
puts big_decimal_sum  # 0.43

BigDecimal is the standard choice for financial arithmetic, where accumulated rounding error is not acceptable.

Tolerance comparison

tolerance = 0.0001
puts (sum - 0.43).abs <= tolerance  # true

If you’re stuck with floats, compare within a tolerance instead of with ==.

The principle

Floating point is fine for most calculations and wrong for exact decimal ones. If the answer needs to be exactly 0.43 and not 0.43000000000000004, that’s a sign to reach for Rational or BigDecimal, not to add more decimal places and hope.