Дробные числа: почему 0,1 + 0,2 не равно 0,3

Как устроены двоичные дроби, почему 0,1 нельзя записать в двоичной системе точно, что такое мантисса и порядок в стандарте IEEE 754 и как не попасть в ловушку при сравнении дробных чисел.

Содержание

Компьютер записывает дробные числа в двоичной системе и отводит на каждое фиксированное количество битов. Числа 0,1 и 0,2 в двоичной записи оказываются бесконечными дробями, поэтому в память попадают их приближения. При сложении крошечные неточности складываются, и вместо 0,3 получается 0,30000000000000004.

Двоичные дроби

В десятичной записи разряды после запятой — это десятые, сотые и тысячные. В двоичной каждый следующий разряд вдвое мельче предыдущего: половина, четверть, восьмая.

TXT
цифра   1   0   1 , 1    0    1
вес     4   2   1   1/2  1/4  1/8

Складываем веса там, где стоят единицы: 4 + 1 + 1/2 + 1/8 = 5,625. Значит, 101,101₂ = 5,625.

Чтобы перевести дробь в двоичную запись, её умножают на два и выписывают целую часть: она и есть очередная цифра. Затем то же самое делают с остатком. Переведём 0,375.

TXT
0,375 · 2 = 0,75    цифра 0
0,75  · 2 = 1,5     цифра 1, остаётся 0,5
0,5   · 2 = 1,0     цифра 1, остаётся 0

Цифры читаем сверху вниз: 0,375 = 0,011₂, то есть четверть плюс одна восьмая.

Почему 0,1 не записать точно

Попробуйте записать одну треть десятичной дробью. Получится 0,333… — тройки не закончатся никогда. Десятичная дробь бывает конечной, только если число складывается из десятых, сотых, тысячных.

В двоичной системе правило то же, но «кирпичики» другие: половины, четверти, восьмые и так далее. Разрежьте пиццу пополам, потом каждый кусок ещё пополам, и ещё. Получатся куски в 1/2, 1/4, 1/8, 1/16 пиццы, но ровно десятую часть из них не собрать, сколько ни режь.

Проверим умножением:

TXT
0,1 · 2 = 0,2    цифра 0
0,2 · 2 = 0,4    цифра 0
0,4 · 2 = 0,8    цифра 0
0,8 · 2 = 1,6    цифра 1, остаётся 0,6
0,6 · 2 = 1,2    цифра 1, остаётся 0,2
0,2 · 2 = 0,4    цифра 0 — это уже было, дальше всё повторяется

Выходит 0,1 = 0,0001100110011…₂: группа 0011 повторяется без конца. В любое конечное число битов такая дробь целиком не поместится.

Фиксированная точка

Самый простой способ хранить дроби — договориться, сколько последних разрядов считать дробными. Так поступают с деньгами: цену 199,90 ₽ записывают как 19 990 копеек. В памяти лежит обычное целое число, а запятая стоит на одном и том же месте. Это фиксированная точка.

Способ точный, но негибкий. Формат, в котором на всё число отведено восемь цифр и две из них дробные, не годится ни для толщины волоса в метрах, ни для расстояния до Солнца.

Плавающая точка

Учёные записывают очень большие и очень маленькие числа одинаково коротко. Например, в одном моле вещества примерно 6,02 · 10²³ молекул. В такой записи три части: знак, значащие цифры и показатель степени, который говорит, куда сдвинуть запятую. Запятая «плавает», поэтому способ называют плавающей точкой или плавающей запятой.

Компьютер делает то же самое в двоичной системе. Число записывается как 1,… · 2ⁿ. Значащие цифры называют мантиссой, показатель степени — порядком. Возьмём знакомое число:

TXT
5,625 = 101,101₂ = 1,01101₂ · 2²

Как разложить эти части по битам, определяет стандарт IEEE 754, принятый в 1985 году. Ему следуют почти все процессоры и языки программирования.

ФорматВсего битовЗнакПорядокМантиссаТочность
одинарная точность321823около 7 десятичных цифр
двойная точность6411152около 16 десятичных цифр
32 бита числа 5,625: один бит знака равен 0, восемь битов порядка 10000001, двадцать три бита мантиссы начинаются с 01101
Рисунок 1 — Число 5,625 в формате одинарной точности: знак, порядок и мантисса

На схеме видны две хитрости стандарта. Порядок хранится со сдвигом: в 32-битном формате к нему прибавляют 127, чтобы не возиться с отрицательными показателями. Поэтому вместо 2 записано 129. А единицу перед запятой не хранят вовсе: она там всегда, и на ней экономят бит. Мы упростили картину: у стандарта есть ещё особые записи для нуля и бесконечности.

Тот самый пример

Попросите почти любой язык программирования сложить 0,1 и 0,2. Вот что отвечает Python, где дробные числа занимают 64 бита:

Python
>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False

Бесконечный хвост каждой дроби пришлось обрезать. В памяти лежат не сами числа, а ближайшие к ним соседи:

TXT
вместо 0,1      0,1000000000000000055511151231257827…
вместо 0,2      0,2000000000000000111022302462515654…
их сумма        0,3000000000000000444089209850062616…
вместо 0,3      0,2999999999999999888977697537484345…

Сумма и «компьютерные» 0,3 — два разных числа. Они отличаются только в семнадцатом знаке после запятой, но сравнение на равенство мелочей не прощает.

Отсюда три практических правила.

  1. Не сравнивайте дробные числа на точное равенство. Проверяйте, что разница между ними меньше заранее выбранной малой величины, например одной миллионной.
  2. Деньги храните целыми числами — в копейках. Иначе цена 19,99, умноженная на 100, превратится в 1998,9999999999998.
  3. Помните, что у больших чисел точность грубее. В формате одинарной точности значащих битов 24, поэтому подряд идут только целые числа до 2²⁴ = 16 777 216. Число 16 777 217 в такой формат уже не помещается: соседние значения идут с шагом 2, и 16 777 216 + 1 снова даёт 16 777 216.

Частые вопросы

Это ошибка Python?

Нет. Так же ведут себя JavaScript, C++, Java и другие языки: все они используют один стандарт и одни и те же схемы процессора.

Неточны все дробные числа?

Нет. Числа, которые складываются из нескольких половин, четвертей, восьмых и так далее, хранятся точно. Поэтому 0,5 + 0,25 даёт ровно 0,75.

Почему калькулятор показывает 0,3?

Как правило, перед выводом он округляет ответ до нескольких знаков, и далёкий семнадцатый знак на экран просто не попадает.

Коротко

  • В двоичной дроби разряды после запятой весят 1/2, 1/4, 1/8 и так далее.
  • Число 0,1 в двоичной системе — бесконечная дробь, поэтому в памяти хранится его приближение.
  • Число с плавающей точкой состоит из знака, порядка и мантиссы; в 32 битах это 1 + 8 + 23 бита, в 64 — 1 + 11 + 52.
  • 0,1 + 0,2 в 64-битных числах равно 0,30000000000000004, поэтому дроби не сравнивают на точное равенство.
  • Деньги хранят целыми числами, а большие числа с плавающей точкой теряют младшие разряды.

Числа и текст компьютер хранить умеет. Осталось понять, как в те же байты превращаются фотография и песня, — об этом урок Картинки и звук.

Использованная литература

  1. Число с плавающей запятой — Википедия [Электронный ресурс]. — URL: https://ru.wikipedia.org/wiki/Число_с_плавающей_запятой (дата обращения: 09.10.2026).
  2. IEEE 754-2008 — Википедия [Электронный ресурс]. — URL: https://ru.wikipedia.org/wiki/IEEE_754-2008 (дата обращения: 09.10.2026).
  3. Floating-Point Arithmetic: Issues and Limitations — документация Python [Электронный ресурс]. — URL: https://docs.python.org/3/tutorial/floatingpoint.html (дата обращения: 09.10.2026).