Open a Python prompt and type 0.1 + 0.2. You expect 0.3. You get something slightly different:
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False
Nothing is broken. Python, JavaScript, Java, Rust and C all give you the same answer when they add two ordinary decimal numbers, because they all store them in the same format. To see why, we need to look at how a computer holds a number like 0.1.
A computer stores everything as bits, which are 0s and 1s. For whole numbers that is easy. For fractions, each place after the point is worth half of the one before: a half, a quarter, an eighth, a sixteenth, and so on. So 0.75 is just a half plus a quarter, which is exact:
print(0.5 + 0.25 == 0.75) # True
Now try 0.1. No pile of halves, quarters and eighths adds up to exactly one tenth. In binary, 0.1 goes on forever, like this: 0.0001100110011001100..., repeating 0011 without end. You may know the same thing in decimal: one third is 0.3333... forever, and nobody can write it out in full. Tenths are tidy for people who count in tens, but binary has the same problem with them that decimal has with thirds.
The standard way to store a decimal number is called a double (short for double-precision float, defined by a standard called IEEE 754). A double has 64 bits, split into three parts: 1 sign bit, 11 exponent bits (where the point sits) and 52 fraction bits (the digits). That gives about 53 significant binary digits. When a number needs more, the computer rounds to the closest one it can hold.
So when you type 0.1, what is stored is the nearest double, which is very slightly too big. Python can show us the exact value:
from decimal import Decimal
print(Decimal(0.1))
print(Decimal(0.2))
print(Decimal(0.3))
0.1000000000000000055511151231257827021181583404541015625
0.200000000000000011102230246251565404236316680908203125
0.299999999999999988897769753748434595763683319091796875
The 0.1 you typed is really 0.1000000000000000055..., and the 0.3 is a touch too small. The error is tiny, smaller than one part in 1016, but it is there. Try it yourself below.
Press the 0.1 + 0.2 button above and compare the cards. The computer adds the two stored values, not the ones you typed. In perfect maths, those add up to exactly 0.3000000000000000166533453693773481063544750213623046875. Doubles near 0.3 sit on a grid with gaps of about 5.55 × 10-17, and that exact sum falls precisely halfway between two grid points. Such a tie is settled by a rule called round-half-to-even, which picks the upper one: 0.3000000000000000444.... That is a different double from the one you get by typing 0.3 (0.29999999999999998889...), so == says they are not equal. When Python prints it, it uses the shortest text that reads back as that same double, and that text is 0.30000000000000004.
Each step is correct. The surprise comes from expecting a decimal answer from a binary machine.
The fix depends on what the numbers mean:
Comparing measurements or results. Never use == on decimals that came out of arithmetic. Ask whether they are close enough:
import math
print(math.isclose(0.1 + 0.2, 0.3)) # True
Showing a number. Round only when you print it. The stored value stays as it is:
print(f"{0.1 + 0.2:.2f}") # 0.30
Money. Store whole cents as integers, which are always exact, and divide only for display. Python also has an exact-decimal type for when you need one:
print(10 + 20 == 30) # True (cents)
from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2")) # 0.3
Notice that Decimal is given the text "0.1". If you gave it the float 0.1, it would faithfully keep the long expansion shown earlier.
Doubles hold about 15 to 17 significant decimal digits, so small errors are normal and usually harmless. Fractions made of halves are exact; most tenths are not. Compare with a tolerance, round when you display, and use integers or Decimal for money. As of 2026 this is true of every mainstream language, so you will meet it again wherever you go.