zez*_*llo 7 python decimal python-3.x
用简单的ints:
>>> -45 % 360
315
Run Code Online (Sandbox Code Playgroud)
然而,使用decimal.Decimal:
>>> from decimal import Decimal
>>> Decimal('-45') % 360
Decimal('-45')
Run Code Online (Sandbox Code Playgroud)
我希望得到Decimal('315').
这有什么理由吗?有没有办法获得一致的行为(没有修补decimal.Decimal)?(我没有改变上下文,也找不到如何改变它来解决这种情况).
经过长时间的搜索(因为搜索"%","mod","modulo"等给出了一千个结果),我终于发现,令人惊讶的是,这是有意的:
算术对十进制对象和算术对整数和浮点数有一些小的差别.当余数运算符%应用于Decimal对象时,结果的符号是被除数的符号,而不是除数的符号:
Run Code Online (Sandbox Code Playgroud)>>> (-7) % 4 1 >>> Decimal(-7) % Decimal(4) Decimal('-3')
我不知道这个的原因,但看起来不可能改变这种行为(没有修补).
Python的行为符合IBM的通用十进制算术规范。
的余数被定义为:
余数取两个操作数;它返回整数除法的余数。[…]
结果是对除整数进行描述的整数除法运算后的红利残差,必要时四舍五入为精确数字。结果的符号(如果非零)与原始除数的符号相同。
所以因为Decimal('-45') // D('360')是Decimal('-0'),其余的只能是Decimal('-45')。
虽然为什么商是0而不是-1?该规范说:
除整数采用两个操作数;它将两个数字相除并返回结果的整数部分。[…]
返回的结果定义为在股息大于或等于除数的情况下,从股息中重复减去除数的结果。在此减法过程中,将使用除数和除数的绝对值:最终结果的符号与使用正态除法时将得到的符号相同。[…]
注意:[…]
- 定义除整数和余数运算,以便可以将它们计算为标准除法运算(如上所述)的副产品。一旦得到整数结果,除法过程即告结束;股息的余数就是余数。
您可以从45中减去360?0次 整数结果可用吗?它是。然后商为零且带负号,因为除法运算表明
该标志的结果是异或的操作数的迹象。
至于为什么使用十进制规范,而不是像数学中那样,其余部分总是为正,我推测这可能是为了简化减法算法。无需检查操作数的符号即可计算商的绝对值。无论如何,现代实现可能都使用更复杂的算法,但是在标准形成和硬件更简单(晶体管更少)的时代,简化可能是一个重要因素。有趣的事实:随着Penryn的发布,英特尔仅在2007年从radix-2整数除法转换为radix-16 。