Skip to content
Theory · Operators · lesson 3 of 9

Floating-point numbers

Try writing one third as a decimal fraction on paper. You get 0.333…, and the threes never end. You have to stop somewhere, say at 0.333. Add three such numbers and you get 0.999, not one.

A computer falls into the same trap, only it counts in binary. Fractional numbers of type float are stored in binary, and most decimal fractions cannot be written that way exactly. So the sum of two short fractions may differ from the one on paper:

Python
price = 0.1
fee = 0.2
total = price + fee
print(total)  # 0.30000000000000004
print(total == 0.3)  # False

Let's see what happened here:

  1. The first two lines put 0.1 and 0.2 into variables.
  2. total = price + fee adds them.
  3. print(total) prints 0.30000000000000004, with an extra four at the end.
  4. print(total == 0.3) prints False.

The == operator compares two values: it gives True if they are equal and False if they are not. Here it gave False, because an error crept into the last digit of the sum.

How a fraction is stored

Such numbers are called floating-point numbers. They keep about 16 significant digits, and a separate factor sets where the point goes. That is why a float holds both 0.000001 and trillions, but almost every fraction in it is approximate.

Memory holds the binary number closest to 0.1 instead of 0.1 itself, and the same goes for 0.2. Two tiny rounding errors added up and became visible. print shows the shortest notation that gives the same number, so print(0.1) prints 0.1 without a long tail.

The one-third analogy has a limit: in binary, the awkward fractions are different ones. 0.5 and 0.25 are stored exactly, and 0.5 + 0.25 gives exactly 0.75. But 0.1 in binary is an endless fraction, like one third in decimal.

Interviewers like to ask this: "Why does 0.1 + 0.2 not equal 0.3?" A good answer names binary storage, the rounding error and a way to compare such numbers.

Integers of type int are stored exactly, however many digits they have. That is why amounts of money are counted in cents, as integers.

Rounding and comparing

Comparing fractional numbers with == is unreliable. Python has two tools for it.

The round function

The round(x, n) function rounds a fractional x to n digits after the point and returns a float. Without the second argument, it returns the nearest whole number of type int:

Python
total = 0.1 + 0.2
print(round(total, 2))  # 0.3
print(round(total, 2) == 0.3)  # True
print(round(3.7), round(-3.7))  # 4 -4

Let's go line by line:

  1. round(total, 2) prints 0.3: the tail of zeros and the four is gone.
  2. Comparing the rounded sum with 0.3 gives True.
  3. round(3.7) and round(-3.7) give the whole numbers 4 and -4.

The rounded sum is the same binary number closest to 0.3 that the notation 0.3 in the code gives. So the second comparison holds.

The math.isclose function

Rounding before every comparison is awkward: you have to guess the number of digits. The math.isclose function tells whether two numbers are equal, allowing for a tiny error. The line import math at the top loads the module math, a ready-made set of math functions, and isclose is one of them:

Python
import math

print(math.isclose(0.1 + 0.2, 0.3))  # True
print(math.isclose(0.3, 0.31))  # False

isclose treats numbers as equal if they differ by at most a billionth of the larger one. So 0.1 + 0.2 and 0.3 are equal for it, but 0.3 and 0.31 are not. Fractional answers in the course exercises are checked the same way.

Common mistake

round is expected to round a half up, as in school:

Python
price = 2.5
rounded = round(price)  # ✗
print(rounded)  # 2

There is no error, but the result is 2, not 3. Python rounds an exact half to the nearest even number: round(1.5) and round(2.5) both give 2. That way, over many roundings, errors up and down balance each other out. For a positive number, int(price + 0.5) rounds a half up, giving 3.

Key points

  • A float stores a fraction in binary approximately, so 0.1 + 0.2 prints 0.30000000000000004.
  • Computed fractional numbers are not compared with ==: use round or math.isclose.
  • round rounds an exact half to even: round(2.5) gives 2.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way