десятичный.Decimal (n) % 1 возвращает InvalidOperation, DivisionImpossible для всех n>= 100
Я использую десятичные объекты в приложении django и обнаружил эту странную ошибку:
ipdb> decimal.Decimal(10) % 1
Decimal('0')
ipdb> decimal.Decimal(100) % 1
*** decimal.InvalidOperation: [<class 'decimal.DivisionImpossible'>]
ipdb> decimal.Decimal(150) % 1
*** decimal.InvalidOperation: [<class 'decimal.DivisionImpossible'>]
ipdb> decimal.Decimal(79) % 1
Decimal('0')
ipdb> decimal.Decimal(100.1) % 2
Decimal('0.10')
ipdb> decimal.Decimal(1000) % 2
*** decimal.InvalidOperation: [<class 'decimal.DivisionImpossible'>]
еще более загадочно, это не происходит в ipython, пока цифры не станут очень большими:
In [23]: decimal.Decimal(10**27) % 1
Out[23]: Decimal('0')
In [24]: decimal.Decimal(10**28) % 1
---------------------------------------------------------------------------
InvalidOperation Traceback (most recent call last)
<ipython-input-24-6ceaef82d283> in <module>()
----> 1 decimal.Decimal(10**28) % 1
InvalidOperation: [<class 'decimal.DivisionImpossible'>]
обратите внимание, что ошибка не ограничивается ipdb: я обнаружил это, потому что Decimal(380) % 1 нарушал мое приложение django.
на документация описывая эту ошибку, говорит:
разделение невозможно
это происходит и сигнализирует недопустимую операцию, если целочисленный результат операции деления целого числа или остатка имел слишком много цифр (было бы больше точности). В результате получается [0, qNaN].
какие идеи?
1 ответов
кажется, я понял.
смотреть на!--7-->исходный код, я нашел это:
# catch most cases of large or small quotient
expdiff = self.adjusted() - other.adjusted()
if expdiff >= context.prec + 1:
# expdiff >= prec+1 => abs(self/other) > 10**prec
return context._raise_error(DivisionImpossible)
if expdiff <= -2:
# expdiff <= -2 => abs(self/other) < 0.1
ans = self._rescale(ideal_exponent, context.rounding)
return ans._fix(context)
и в моем приложении django есть настройка prec:
decimal.getcontext().prec = 2
Это все еще выглядит немного неправильно для меня, потому что:
In [39]: decimal.getcontext().prec + 1
Out[39]: 3
In [40]: decimal.Decimal(100).adjusted() - decimal.Decimal(0).adjusted()
Out[40]: 2
и поэтому все еще похоже, что 100 находится в пределах того ,что он проверяет (то есть,2 < 3
), но я уверен, что это источник проблемы. Если кто-нибудь может просветить меня, почему библиотека делает это, я хотел бы понять это лучше.