Почему 0.1 + 0.2 не равно ровно 0.3
Самый знаменитый «сюрприз» float — и совершенно логичное, точное объяснение, почему он происходит.
Один из самых знаменитых «сюрпризов» Python — да и практически любого языка программирования:
print(0.1 + 0.2)
0.30000000000000004
Простая аналогия: 1/3 в десятичной записи
В десятичной системе 1/3 нельзя записать конечным числом
цифр — только 0.333333..., до бесконечности. Не потому, что
десятичная система «плохая» — просто у неё есть числа, которые она не может выразить точно
конечной записью.
У компьютера в двоичной системе — точно такая же проблема, только с другими числами.
0.1 в десятичной записи выглядит «простым» — но в двоичной
системе он превращается в бесконечно повторяющуюся дробь, совсем как 1/3
в десятичной. Компьютер вынужден её обрезать до конечного числа битов — отсюда и крошечная
погрешность.
Что происходит глубже
На большинстве современных компьютеров и в стандартном CPython
float соответствует аппаратному формату двойной точности,
известному как binary64 (часть стандарта IEEE 754). Концептуально число
хранится тремя частями:
Python может показать точное сохранённое значение
Хорошая новость: приближение не случайно и не загадочно — Python может показать вам, что именно хранится:
print((0.1).as_integer_ratio())
# (3602879701896397, 36028797018963968) — точная дробь, которая реально хранится
print((0.1).hex())
# '0x1.999999999999ap-4' — точное представление в шестнадцатеричном виде