Глава 4 · Python любит числа

Почему 0.1 + 0.2 не равно ровно 0.3

Самый знаменитый «сюрприз» float — и совершенно логичное, точное объяснение, почему он происходит.

Один из самых знаменитых «сюрпризов» Python — да и практически любого языка программирования:

surpriz.py
print(0.1 + 0.2)
Реальный вывод
0.30000000000000004
Это не баг Python
Точно такое же поведение вы увидите в JavaScript, Java, C, C++ и почти любом другом распространённом языке. Причина — не ошибка Python, а то, как ЛЮБОЙ компьютер хранит дробные числа в двоичном виде.

Простая аналогия: 1/3 в десятичной записи

В десятичной системе 1/3 нельзя записать конечным числом цифр — только 0.333333..., до бесконечности. Не потому, что десятичная система «плохая» — просто у неё есть числа, которые она не может выразить точно конечной записью.

У компьютера в двоичной системе — точно такая же проблема, только с другими числами. 0.1 в десятичной записи выглядит «простым» — но в двоичной системе он превращается в бесконечно повторяющуюся дробь, совсем как 1/3 в десятичной. Компьютер вынужден её обрезать до конечного числа битов — отсюда и крошечная погрешность.

Десятичное 0.1то, что вы написалиБлижайшеедвоичное…то, что реальнохранитсяКрошечная ошибкаразница почти незаметна
0.1 не хранится ровно — хранится ближайшее представимое двоичное приближение

Что происходит глубже

На большинстве современных компьютеров и в стандартном CPython float соответствует аппаратному формату двойной точности, известному как binary64 (часть стандарта IEEE 754). Концептуально число хранится тремя частями:

float (binary64)Знакплюс или минусЭкспонентамасштаб числаМантиссазначащие цифры
Из чего состоит типичный float на современном CPython (стандарт binary64)
Не нужно запоминать наизусть
Точное число битов на каждую часть (1/11/52 в стандарте binary64) — деталь, которую не нужно заучивать прямо сейчас. Важно понимать сам принцип: значение хранится приближённо, а не то, что Python «плохо считает». Это распространённое, хорошо изученное поведение — стандарт binary64, а не собственное правило языка Python.

Python может показать точное сохранённое значение

Хорошая новость: приближение не случайно и не загадочно — Python может показать вам, что именно хранится:

tochnoe.py
print((0.1).as_integer_ratio())
# (3602879701896397, 36028797018963968) — точная дробь, которая реально хранится
hex_predstavlenie.py
print((0.1).hex())
# '0x1.999999999999ap-4' — точное представление в шестнадцатеричном виде
Главный вывод раздела
0.1 хранится не «примерно как получится», а как совершенно точное, предсказуемое и объяснимое приближение — просто не то десятичное число 0.1, которое вы написали. Это приближение, а не случайность.
Практика: 0.1 + 0.2 — исследуем приближение
Интерактивный ноутбук прямо в браузере — as_integer_ratio(), hex() и предсказание результата
Открыть практику →