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

时间:2014-07-20 08:41:11

标签: python

欧几里德定义说,

  

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

根据以下观察,

>>> -3 % -2   # Ideally it should be (-2 * 2) + 1
-1
>>> -3 % 2    # this looks fine, (-2 * 2) + 1 
1
>>> 2 % -3    # Ideally it should be (-3 * 0) + 2
-1

看起来%运算符正在运行不同的规则。

  • link1没有帮助,
  • link2提供递归回答,因为我不明白%的工作原理,因此很难理解(a // b) * b + (a % b) == a的工作方式

我的问题:

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

1 个答案:

答案 0 :(得分:4)

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

  

如果其中一个操作数为负数,则结果为无效,即   圆形远离零(朝向负无穷大):

>>> -5//2
-3
>>> 5//-2
-3
     

这扰乱了一些人,但有一个很好的数学原因。   整数除法运算(//)及其兄弟,模数   操作(%),走到一起,满足一个很好的数学   关系(所有变量都是整数):

     

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.

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

请注意,许多常见的编程语言(C,C ++,Java,...)满足欧几里德不变量,通常在更多情况下而不是python(例如甚至当b为正时)。 其中一些甚至不对剩余部分的符号提供任何保证,将该细节留作实施定义。


作为旁注:Haskell提供两种类型的模块和分区。标准欧氏模数和除法称为remquot,而浮动除法和“蟒蛇样式”模数称为moddiv