У меня большой объем кода на Python, который пытается обрабатывать числа с точностью до 4 десятичных знаков, и я застрял на Python 2.4 по многим причинам. Код выполняет очень упрощенную математику (это код управления кредитами, который в основном берет или добавляет кредиты)
Это смешало использование float и Decimal (MySQLdb возвращает десятичные объекты для типов SQL DECIMAL). После нескольких странных ошибок, появившихся в результате использования, я обнаружил, что первопричиной всего этого является несколько мест в коде, которые плавают и сравниваются десятичные числа.
Я попал в такие случаи:
>>> from decimal import Decimal
>>> max(Decimal('0.06'), 0.6)
Decimal("0.06")
Теперь я боюсь, что я не смогу отследить все такие случаи в коде. (обычный программист будет продолжать делать x> 0 вместо x> Decimal ('0.0000'), и этого очень трудно избежать)
Я разработал патч (вдохновленный улучшениями в десятичном пакете в python 2.7).
import decimal
def _convert_other(other):
"""Convert other to Decimal.
Verifies that it's ok to use in an implicit construction.
"""
if isinstance(other, Decimal):
return other
if isinstance(other, (int, long)):
return Decimal(other)
# Our small patch begins
if isinstance(other, float):
return Decimal(str(other))
# Our small patch ends
return NotImplemented
decimal._convert_other = _convert_other
Я просто делаю это в очень ранней библиотеке загрузки, и она изменит поведение десятичного пакета, допуская преобразование с плавающей запятой в десятичную перед сравнениями (чтобы избежать попадания объекта сравнения по умолчанию в python для сравнения объектов).
Я специально использовал "str" вместо "repr", поскольку это исправляет некоторые случаи округления чисел с плавающей точкой. Э.Г.
>>> Decimal(str(0.6))
Decimal("0.6")
>>> Decimal(repr(0.6))
Decimal("0.59999999999999998")
Теперь мой вопрос:
Я что-то здесь упускаю? Это довольно безопасно? или я что-то здесь нарушаю?
(Я думаю, что у авторов пакета были очень веские причины избегать поплавков)