Сообщить об ошибке.

Ошибки округления с повышенной точностью

Использование десятичного числа с плавающей запятой устраняет ошибку десятичного представления, позволяя точно представить 0,1. Однако некоторые операции могут все еще вызывать ошибку округления, когда ненулевые цифры превышают фиксированную точность decimal.getcontext().prec.

Эффект ошибки округления может быть усилен сложением или вычитанием почти компенсирующих величин, что приводит к потере значимости. Дональд Кнут представил два поучительных примера, где округленная арифметика с плавающей точкой с недостаточной точностью приводит к нарушению ассоциативных и распределительных свойств сложения:

>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8
>>> D =  Decimal
>>> u, v, w = D(11111113), D(-11111111), D('7.51111111')
>>> (u + v) + w
# Decimal('9.5111111')
>>> u + (v + w)
# Decimal('10')

>>> u, v, w = D(20000), D(-6), D('6.0000003')
>>> (u*v) + (u*w)
# Decimal('0.01')
>>> u * (v+w)
# Decimal('0.0060000')

Модуль decimal позволяет восстановить тождества, достаточно увеличив точность, чтобы избежать потери значимости:

>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
# Decimal('9.51111111')
>>> u + (v + w)
# Decimal('9.51111111')

>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
# Decimal('0.0060000')
>>> u * (v+w)
# Decimal('0.0060000')