C和Python中的取模(%)操作行为不同

77 投票
6 回答
26655 浏览
提问于 2025-04-15 17:02

我发现同样的取模操作在不同的编程语言中会产生不同的结果。

在Python中:

-1 % 10

结果是9

而在C语言中,结果是-1

  1. 那么,哪个才是正确的取模结果呢?
  2. 如何让C语言中的取模操作和Python中的一样呢?

6 个回答

18

在C89/90版本中,除法运算符和余数运算符在处理负数时的表现是由实现决定的,这意味着不同的编程环境可能会有不同的结果。只要这两个运算符的结果能相互一致就可以了:从a / b = qa % b = r可以推导出a = b * q + r。如果你的代码依赖于这些运算的结果,建议使用静态断言来检查它们的行为。

到了C99版本,这些运算的行为已经变成了标准。

实际上,这两种行为都有其合理性。Python的行为实现了真正的取模运算。而你在C中观察到的行为则是向0取整的方式(这也是Fortran的行为)。

在C语言中,选择向0取整的原因之一是,这样的结果比较符合直觉。比如,-a / b的结果应该和-(a / b)是一样的。如果采用真正的取模行为,-1 % 10的结果会是9,这样-1 / 10就得是-1。这可能会让人觉得不太自然,因为-(1 / 10)的结果是0。

40

Python有一个“真正的”取模操作,而C语言则有一个余数操作。

这两者的区别主要体现在负数除法的处理上,也就是结果是向0取整还是向负无穷取整。Python是向负无穷取整,而C语言则是向0取整。不过在这两种语言中,(n/m)*m + n%m == n这个关系是成立的,所以取模操作符必须在正确的方向上进行调整。

Ada语言则更明确,它同时有modrem这两种操作。

90
  1. 这两种写法都是对的,不过在数学,特别是数论中,Python的取模运算是最常用的。
  2. 在C语言中,你可以用 ((n % M) + M) % M 来得到和Python一样的结果。例如 ((-1 % 10) + 10) % 10。注意,这个方法对正整数也有效:((17 % 10) + 10) % 10 == 17 % 10,而且对于C语言的两种实现(无论是正余数还是负余数)都适用。

撰写回答