通过应用 (Decimal(), signed numbers ) 在 python 中使用 (%, //) 背后的数学计算?

The math calculations behind using (%, //) in python by applying (Decimal(), signed numbers )?

我试图通过做一些试验来理解使用 / 和 // 和 % 运算符计算背后的数学原理,发现结果仅在使用 Decimal() 时才类似于计算器,但如果没有它,结果有点令人困惑,我试过了在我的代码中添加注释 #No Idea 以标记我不理解的地方,例如:

  1. 在这个 % 运算符的试验中,通过应用有符号和无符号数字的结果以及有和没有 Decimal() 的结果是:

    >>> 9%5    #This result will be the reminder
    4         
    >>> (-9)%5    #No Idea
    1
    >>> Decimal(9)% Decimal(5)    #This result will be the reminder
    Decimal('4')  
    >>> Decimal(-9)% Decimal(5)    #The result will be the signed reminder
    Decimal('-4')
    
  2. 在这个针对 // 运算符的试验中,使用带和不带 Decimal() 的有符号和无符号数,结果是:

    >>> 9//5    #int result
    1
    >>> -9//5    #No Idea
    -2
    >>> Decimal(9)/Decimal(5)    #Same result as using calculator
    Decimal('1.8')
    >>> Decimal(-9)//Decimal(5)    #No Idea
    Decimal('-1')
    

请考虑这个问题不是重复的,我已经做了一些研究来得到答案,但我发现一些回答的问题只解释了 // operator using only positive signed numbers and does not include information about negative numbers有符号数或使用 Decimal() 并且没有关于 % 运算符的答案。

所以,如果有人知道为什么结果不同以及它们是如何计算的,那将会很有帮助。

据我了解,OP 询问的是 Python 整数和 Decimal 之间的不同行为。我认为没有任何充分的理由。两种选择都是可能的,但它们的不同会让用户感到有点困惑。

让我们调用分子n、分母d并将结果拆分为整数结果i和余数r。这意味着

n // d = i
n % d = r

为了使操作有意义,我们需要

i * d + r == n

对于 n = -9d = 5 我们看到 i = -1, r = -4i = -2, r = 1 都支持这一点,正如

所见
(i = -1, r = -4) => -1 * 5 + -4 == -9
(i = -2, r = 1) => -2 * 5 + 1 == -9

现在,在 Python 中,整数除法被定义为始终向负无穷大(向下)截断,并且 Decimal 实现已选择向零舍入。这意味着正值向下 truncated/rounded,而负值向上舍入。

向零四舍五入也是C语言中的选择。但是,我个人认为 Python 选择更加明智,特别是来自硬件背景。鉴于这是在 Python 中做出的选择,我认为 Decimal 选择像在 C 语言中那样做很奇怪(而且很糟糕)。

整数行为的解释

来自 python documentation:

Division of integers yields a float, while floor division of integers results in an integer; the result is that of mathematical division with the ‘floor’ function applied to the result.

因此,负负数和正数的整数除法(//)的工作原理如下:

-9 // 5 == floor(-9 / 5) == floor(-1.8) == -2

模运算符是整数除法的余数,即x % y = x - x // y * y。在你的例子中:

-9 % 5 == -9 - (-9 // 5 * 5) == (-9) - (-2 * 5) == (-9) - (-10) == 1

文档还说:

The modulo operator always yields a result with the same sign as its second operand (or zero); the absolute value of the result is strictly smaller than the absolute value of the second operand.

但这自然来自上面的公式,例如:

9 % -5 == 9 - (9 // (-5) * (-5)) == 9 - (-2 * (-5)) == 9 - 10 == -1

decimal.Decimal不同

The documentation 很好地解释了差异:

There are some small differences between arithmetic on Decimal objects and arithmetic on integers and floats. When the remainder operator % is applied to Decimal objects, the sign of the result is the sign of the dividend rather than the sign of the divisor:

>>> (-7) % 4
1
>>> Decimal(-7) % Decimal(4)
Decimal('-3')

The integer division operator // behaves analogously, returning the integer part of the true quotient (truncating towards zero) rather than its floor, so as to preserve the usual identity x == (x // y) * y + x % y:

>>> -7 // 4
-2
>>> Decimal(-7) // Decimal(4)
Decimal('-1')