为什么 Python 的模运算符 (%) 与欧几里德定义不匹配?

ove*_*nge 3 python

欧几里得的定义说,

\n\n
\n

给定两个整数 a 和 b,且 b \xe2\x89\xa0 0,存在唯一整数 q 和 r,使得 a = bq + r 且 0 \xe2\x89\xa4 r < |b|,其中 |b| 表示b的绝对值。

\n
\n\n

根据以下观察,

\n\n
>>> -3 % -2   # Ideally it should be (-2 * 2) + 1\n-1\n>>> -3 % 2    # this looks fine, (-2 * 2) + 1 \n1\n>>> 2 % -3    # Ideally it should be (-3 * 0) + 2\n-1\n
Run Code Online (Sandbox Code Playgroud)\n\n

看起来%运营商正在按照不同的规则运行。

\n\n
    \n
  • link1没有帮助,
  • \n
  • link2给出了递归答案,因为,由于我不明白如何%工作,所以很难理解如何 (a // b) * b + (a % b) == a工作
  • \n
\n\n

我的问题:

\n\n

我如何理解Python中模运算符的行为?我不知道有关%操作员工作的任何其他语言。

\n

Bak*_*riu 5

The History of Python的一篇文章解释了整数除法和模运算的行为,即:Why Python's Integer Division Floors。我将引用相关部分:

如果其中一个操作数为负,则结果取整,即从零开始舍入(向负无穷大舍入):

>>> -5//2
-3
>>> 5//-2
-3
Run Code Online (Sandbox Code Playgroud)

这让一些人感到不安,但有一个很好的数学原因。整数除法运算 ( //) 及其兄弟模运算 ( %) 一起满足良好的数学关系(所有变量都是整数):

a/b = q与余数r

这样

b*q + r = a0 <= r < b

(假设ab>= 0)。

如果你想让关系延伸为负数a(保持b 正数),你有两种选择:如果你q向零截断,r 就会变成负数,这样不变量就变成了,0 <= abs(r) 否则,你可以q向负无穷大下降,不变量仍然是0 <= r < b

在数学数论中,数学家总是更喜欢后者(参见维基百科)。对于 Python,我做出了同样的选择,因为有一些有趣的模运算应用,其中 a 的符号并不有趣。[...] 顺便说一句,对于负 b,一切都会翻转,不变量变为:

0 >= r > b.
Run Code Online (Sandbox Code Playgroud)

换句话说,Python 决定在某些情况下打破欧几里得定义,以便在有趣的情况下获得更好的行为。特别是负面的a被认为是有趣的,而负面的则不b被认为是有趣的。这是一个完全任意的选择,在语言之间不共享。

请注意,许多常见的编程语言(C,C ++,Java,...)不满足欧几里得不变量,通常比Python更多的情况(例如,即使b是正数)。其中一些甚至不提供有关余数符号的任何保证,将细节保留为实现定义的。


附带说明:Haskell 提供了模数和除法两种类型。标准欧几里得模数和除法称为remquot,而落地除法和“Python 风格”模数称为moddiv