decimal.Decimal(n) % 1 returns InvalidOperation, DivisionImpossible for all n >= 100
decimal.Decimal(n) % 1 returns InvalidOperation, DivisionImpossible for all n >= 100
我在 Django 应用程序中使用 Decimal 对象,发现了这个奇怪的错误:
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 应用程序。
描述此错误的 documentation 说:
Division impossible
This occurs and signals invalid-operation if the integer result of a divide-integer or remainder operation had too many digits (would be longer than precision). The result is [0,qNaN].
有什么想法吗?
我想我明白了。
查看 source code,我发现了这个:
# 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
),但我非常有信心这就是问题的根源。如果有人能为我阐明为什么图书馆这样做,我很乐意更好地理解它。
我在 Django 应用程序中使用 Decimal 对象,发现了这个奇怪的错误:
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 应用程序。
描述此错误的 documentation 说:
Division impossible
This occurs and signals invalid-operation if the integer result of a divide-integer or remainder operation had too many digits (would be longer than precision). The result is [0,qNaN].
有什么想法吗?
我想我明白了。
查看 source code,我发现了这个:
# 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
),但我非常有信心这就是问题的根源。如果有人能为我阐明为什么图书馆这样做,我很乐意更好地理解它。