对python负十进制的模运算.Decimal和一个正int

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)?(我没有改变上下文,也找不到如何改变它来解决这种情况).

zez*_*llo 7

经过长时间的搜索(因为搜索"%","mod","modulo"等给出了一千个结果),我终于发现,令人惊讶的是,这是有意的:

算术对十进制对象和算术对整数和浮点数有一些小的差别.当余数运算符%应用于Decimal对象时,结果的符号是被除数的符号,而不是除数的符号:

>>> (-7) % 4
1
>>> Decimal(-7) % Decimal(4)
Decimal('-3')
Run Code Online (Sandbox Code Playgroud)

我不知道这个的原因,但看起来不可能改变这种行为(没有修补).

  • `Decimal`是否使用`math.fmod()`?他们都有相同的行为.[来自Python文档](https://docs.python.org/3/library/math.html):"因此,使用浮点数时,函数fmod()通常是首选,而Python的x%y是首选在使用整数时." (2认同)

Cri*_*itu 5

Python的行为符合IBM的通用十进制算术规范

余数被定义为:

余数取两个操作数;它返回整数除法的余数。[…]

结果是对除整数进行描述的整数除法运算后的红利残差,必要时四舍五入为精确数字。结果的符号(如果非零)与原始除数的符号相同。

所以因为Decimal('-45') // D('360')Decimal('-0'),其余的只能是Decimal('-45')

虽然为什么商是0而不是-1?该规范说:

除整数采用两个操作数;它将两个数字相除并返回结果的整数部分。[…]

返回的结果定义为在股息大于或等于除数的情况下,从股息中重复减去除数的结果。在此减法过程中,将使用除数和除数的绝对值:最终结果的符号与使用正态除法时将得到的符号相同。[…]

注意:[…]

  1. 定义除整数和余数运算,以便可以将它们计算为标准除法运算(如上所述)的副产品。一旦得到整数结果,除法过程即告结束;股息的余数就是余数。

您可以从45中减去360?0次 整数结果可用吗?它是。然后商为零且带负号,因为除法运算表明

标志的结果是异或的操作数的迹象。

至于为什么使用十进制规范,而不是像数学中那样,其余部分总是为正,我推测这可能是为了简化减法算法。无需检查操作数的符号即可计算商的绝对值。无论如何,现代实现可能都使用更复杂的算法,但是在标准形成和硬件更简单(晶体管更少)的时代,简化可能是一个重要因素。有趣的事实:随着Penryn的发布,英特尔仅在2007年从radix-2整数除法转换为radix-16 。