Python的模运算和余数运算是否相同?

6
在Python文档中,它说:"百分号(模数)运算符返回第一个参数除以第二个参数的余数。"
所以,给定
a % b

据我所知,余数是指将A与B相除后剩下的数字。因此,21 % 3 = 0,而-25 % 23 = -2。

但我不明白的是当A为负数时会发生什么。

-23 % 22

将产生

21

这是第一个与模数-1同余的正整数。但-1是-23%22的余数。所以文档错了吗?在Python中,模运算符%不会产生a%b的余数,而是产生第一个与B同余的正整数?我很困惑。
2个回答

13

有三种不同的明显方法可以定义负数的整数除法,以及三种相应的定义余数的方法:

  • 向下取整除法,商向负无穷取整,余数与除数具有相同的符号。
  • 截断除法,商朝零截断,余数与被除数具有相同的符号。
  • 欧几里得除法,商以使余数为正的方向朝任意方向截断。

所有这三种方法都保留整数除法的基本定律:

dividend = divisor * quotient + remainder

所以,这三个都不是“对”或“错”。

当然,这并不能阻止人们进行圣战。Knuth基于“数学正确性”的观点主张使用向下取整除法。Wirth则主张使用截断除法,因为它“不那么令人惊讶”。Raymond Boute认为,整数除法是根据欧几里得算法定义的。我不会尝试通过争论他们三个(包括该领域中最重要的两个人)的错误来解决几十年的圣战……

一些语言通过具有两个不同的函数来解决此问题。

我们只需要说Python选择了Knuth的定义,因此其模运算符具有除数的符号。


当然,选择不匹配的商和余数定义又是另一回事了。 或者更糟糕的是,在C99之前,指定一个并将另一个实现定义为未定义的情况。

**这特别有趣,因为它们并不总是在哪个是哪个方面保持一致。至少当它们被称为remmod时,rem是与div相对应的,而mod是与向下取整或欧几里得除法不相对应的,当它们被称为remremaindermodmodulo时......


“维基百科”比我更好地解释了这个问题。 - abarnert

0
如果你把-23除以22,你会得到-23 = -2 * 22 + 21。在Python中,“余数”始终介于0和除数之间(但不等于除数)。对于正除数,商和模通常按照数学定义。在一些编程语言中,使用正除数的负余数,但在Python中不是这样。

谢谢Abarnert。我已编辑我的答案,以便针对负除数也是正确的(希望如此)。 - Steve Kass

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接