Python rounding error with float numbers [duplicate]
Ошибка округления Python с числами с плавающей точкой [дубликат]
Я не знаю, является ли это очевидной ошибкой, но при запуске скрипта Python для изменения параметров моделирования я понял, что результаты с delta = 0.29 и delta = 0.58 отсутствуют. При расследовании я заметил, что следующий код Python:
for i_delta inrange(0, 101, 1): delta = float(i_delta) / 100
(...)
filename = 'foo' + str(int(delta * 100)) + '.dat'
сгенерированы идентичные файлы для delta = 0.28 и 0.29, то же самое для .57 и .58, причина в том, что python возвращает float(29) / 100 как 0.289999999999998. Но это не систематическая ошибка, не в том смысле, что это происходит с каждым целым числом. Итак, я создал следующий скрипт на Python:
import sys
n = int(sys.argv[1])
for i inrange(0, n + 1): a = int(100 * (float(i) / 100)) if i != a: print i, a
И я не вижу никакой закономерности в числах, для которых возникает эта ошибка округления. Почему это происходит с этими конкретными числами?
Переведено автоматически
Ответ 1
Любое число, которое не может быть построено из точных степеней двойки, не может быть представлено точно как число с плавающей запятой; его необходимо аппроксимировать. Иногда максимальное приближение будет меньше фактического числа.
В общем случае десятичная система счисления, вероятно, перегибает палку и по-прежнему будет иметь ошибки округления в редких случаях, когда число не имеет конечного десятичного представления (например, любая дробь, где знаменатель не равен 1 или не делится на 2 или 5 - множители десятичной базы (10)). Например:
>>> s = Decimal(7) >>> Decimal(1)/s/s/s/s/s/s/s*s*s*s*s*s*s*s Decimal('0.9999999999999999999999999996') >>> int(Decimal('0.9999999999999999999999999996')) 0
Поэтому лучше всегда просто округлять перед преобразованием чисел с плавающей точкой в целые числа, если только вам не нужна функция floor.
>>> int(1.9999) 1 >>> int(round(1.999)) 2
Другой альтернативой является использование класса Fraction из библиотеки fraction, который не является аппроксимирующим. (Он просто продолжает добавлять / вычитать и умножать целые числители и знаменатели по мере необходимости).