使用简单的int
s:
>>> -45 % 360
315
然而,使用decimal.Decimal
:
>>> from decimal import Decimal
>>> Decimal('-45') % 360
Decimal('-45')
我希望得到Decimal('315')
。
这有什么理由吗?有没有办法获得一致的行为(没有修补decimal.Decimal
)? (我没有改变上下文,也找不到如何改变它来解决这种情况。)
答案 0 :(得分:7)
经过长时间的搜索(因为搜索“%”,“mod”,“modulo”等会得到一千个结果),我终于发现,令人惊讶的是,this is intended:
Decimal对象上的算术之间存在一些小的差异 和整数和浮点数的算术。当余数运算符% 应用于Decimal对象,结果的符号是符号 红利而不是除数的标志:
>>> (-7) % 4 1 >>> Decimal(-7) % Decimal(4) Decimal('-3')
我不知道原因,但看起来不可能改变这种行为(没有修补)。
答案 1 :(得分:5)
Python的行为符合IBM的General Decimal Arithmetic Specification。
remainder定义为:
余数需要两个操作数;它返回整数除法的余数。 [...]
结果是在divide-integer所述的计算整数除法运算之后的被除数残差,必要时四舍五入为精确数字。结果的符号,如果非零,则与原始股息的符号相同。
因为Decimal('-45') // D('360')
是Decimal('-0')
,其余部分只能是Decimal('-45')
。
虽然为什么商0而不是-1? specification说:
除以整数需要两个操作数;它除以两个数字并返回结果的整数部分。 [...]
返回的结果被定义为在被除数大于或等于除数时从被除数中重复减去除数所得到的结果。在此减法期间,使用被除数和除数的绝对值:最终结果的符号与使用正常除法时得到的符号相同。 [...]
注意:[...]
- 定义除数整数和余数运算,以便可以将它们计算为标准division运算的副产品(如上所述)。只要整数结果可用,分割过程就会结束;股息的剩余部分是余数。
醇>
你可以从45减去360多少次? 0次是否有整数结果?它是。那么商为0,带有减号,因为divide操作表示
结果的符号是操作数符号的独占或。
至于为什么十进制规范采用这种方式,而不是像数学中那样,其余部分总是正数,我猜测它可能是为了简化减法算法。无需检查操作数的符号以计算商的绝对值。现代实现可能无论如何都使用更复杂的算法,但在标准形成和硬件更简单(更少的晶体管)的时代,简单性可能会有一个重要因素。有趣的事实:英特尔仅在2007年从发布Penryn时从基数为2的整数除法转换为基数为16。