Почему round(2.675, 2) даёт 2.67

Почему round(2.675, 2) даёт 2.67

@python_quiz

Разберем этот квиз

Коротко: код в квизе выводит 2.67. Это выглядит неожиданно, потому что в десятичной математике 2.675 должно округляться до 2.68 при стандартном округлении до двух знаков. Разберёмся, почему так происходит и как получить ожидаемый результат при необходимости.

Условие (код из квиза)

python

При выполнении вы увидите:

Причина — представление чисел с плавающей точкой

Компьютеры хранят числа с плавающей точкой в двоичной форме. Десятичные дроби, такие как 0.675, часто не имеют точного двоичного представления и сохраняются как близкое, но не ровное значение. В случае 2.675 фактическое значение в памяти чуть меньше, чем 2.675 (примерно 2.6749999999999998). Поэтому операция округления уже не «попадает на ровную половинку», и стандартное округление даёт 2.67.

Покажем это на практике.

Демонстрация: как выглядит число в памяти

python

Типичный вывод:

Как видно, float хранит чуть меньшее значение, поэтому round(…) возвращает 2.67.

Влияние правила округления Python

Важно: в Python округление "round" использует правило «round half to even» (банковское округление) при работе с числами, которые ровно попадают на половину. В данном случае ничей "половинки" не происходит из‑за двоичной ошибки представления — число меньше половины, и конечный результат 2.67 получается независимо от правила для половин.

Как получить ожидаемое 2.68

Если вам нужно корректно работать с десятичными значениями (например, в финансовых вычислениях), используйте модуль decimal и создавайте Decimal из строки, а не из float. Примеры:

python

Выводы:

  • Decimal('2.675').quantize(Decimal('0.01')) → 2.68
  • Decimal(2.675).quantize(Decimal('0.01')) → повлияет двоичная неточность и даст 2.67

Разбор вариантов (пояснение к возможным ответам)

  • 2.67 — именно это выведет код на языке Python с использованием float и round.
  • 2.68 — интуитивно ожидаемый результат при работе в точной десятичной арифметике; достигается при использовании Decimal('2.675').
  • 2.70 — неверно, такое округление использовало бы другой порядок или ошибку.
  • Ошибка округления — нет, ошибок выполнения нет; просто особенность представления и округления.

Рекомендации

  • Для финансовых и других критичных к точности задач используйте decimal.Decimal и создавайте числа из строк.
  • Если используете float и вам нужно контролировать формат вывода, применяйте форматирование (f-strings или format) — но помните, что это форматирование визуальное, а не исправление внутренней погрешности.
  • Не доверяйте числам с плавающей точкой наивно при сравнении на равенство или при строгом округлении; при необходимости приводите к Decimal или выполняйте округление с контролем правила (half-up, half-even и т.д.).

Если нужно, могу показать дополнительные способы безопасного округления (например, для массовых вычислений или CSV-файлов) и сравнить различные правила округления на примерах.

Report Page