десятичный.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), но я уверен, что это источник проблемы. Если кто-нибудь может просветить меня, почему библиотека делает это, я хотел бы понять это лучше.