C和Python - 模数(%)操作的不同行为

时间:2009-12-15 13:46:07

标签: python c math modulo

我发现相同的mod操作会产生不同的结果,具体取决于使用的语言。

在Python中:

-1 % 10

产生 9

在C中它产生 -1

  1. 哪一个是正确的模数?
  2. 如何使C中的mod操作与Python中的相同?

5 个答案:

答案 0 :(得分:67)

  1. 两种变体都是正确的,但在数学(特别是数论)中,Python modulo是最常用的。
  2. 在C中,您执行((n % M) + M) % M以获得与Python相同的结果。 E. g。 ((-1 % 10) + 10) % 10。注意,它对于正整数仍然有效:((17 % 10) + 10) % 10 == 17 % 10,以及C实现的两种变体(正或负余数)。

答案 1 :(得分:30)

Python有一个“真正的”模运算,而C有一个余数运算。

它与负整数除法的处理方式有直接关系,即向0或负无穷圆舍入。 Python向负无穷而C(99)向0舍入,但在两种语言(n/m)*m + n%m == n中,%运算符必须以正确的方向进行补偿。

Ada更明确,同时具有modrem

答案 2 :(得分:15)

在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。

答案 3 :(得分:4)

这两个答案都是正确的,因为-1 modulo 109 modulo 10相同。

r = (a mod m)
a = n*q + r

您可以确定|r| < |n|,但不确定r的价值。有2个答案,消极和积极。


在C89中,尽管答案总是正确的,但是模运算的确切值(它们称为余数)是未定义的,这意味着它可以是否定结果或正结果。在C99中,定义了结果。

如果你想要肯定的答案,如果你发现你的答案是否定的,你可以简单地加10。

要让模运算符在所有语言上都运行相同,请记住:

n mod M == (n + M) mod M

一般来说:

n mod M == (n + X * M) mod M

答案 4 :(得分:1)

执行欧几里得除法a = b*q + r就像将小数a/b舍入为整数商q,然后计算余数r

您看到的不同结果取决于用于四舍五入的商...

如果您朝零取整(截断),您将得到与C相似的零对称性:

truncate(7/3) = 2
7 = 3*2 + 1

truncate(-7/3) = -2
-7 = 3* -2 - 1

truncate(7/-3) = -2
7 = -3* -2 + 1

如果您朝负无穷大(底数)四舍五入,您将获得与Python一样的余数:

floor(7/3) = 2
7 = 3*2 + 1

floor(-7/3) = -3
-7 = 3* -3 + 2

floor(7/-3) = -3
7 = -3* -3 - 2

如果您舍入到最接近的整数(与您想要的整数相关,等于,等于或远离零),您将获得居中的模数:

round(7/3) = 2
7 = 3*2 + 1

round(8/3) = 3
8 = 3*3 - 1

round(-7/3) = -2
-7 = 3* -2 - 1

round(7/-3) = -2
7 = -3* -2 + 1

您可以尝试通过对正无穷大(ceil)取整来实现自己的模,并且会发明一个非常规的模,但是它仍然是一种模...... p >