在Python中:
-1 % 10
产生结果9
在C中它产生-1!
- 哪个是正确的模?
- 如何让C中的模运算与Python相同?
((n % M) + M) % M
来得到与Python相同的结果。例如:((-1 % 10) + 10) % 10
。请注意,它仍适用于正整数:((17 % 10) + 10) % 10 == 17 % 10
,以及C实现的两种变体(正余数或负余数)。Python拥有“真实”的取模运算,而C则有一个余数运算。
这与如何处理负整数除法有直接关系,即向0或向负无穷舍入。Python向负无穷舍入,而C(99)向0舍入,但在两种语言中都有 (n/m)*m + n%m == n
,因此%运算符必须以正确的方向进行补偿。
Ada更为明确,它同时具有mod
和rem
两种方式。
在C89/90中,负数除法运算符和取余运算符的行为是实现定义的,这意味着根据实现的不同,您可以得到两种不同的行为。只需要确保运算符彼此一致:从a / b = q
和a % 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。
两个答案都是正确的,因为-1模10
与9模10
相同。
r = (a mod m)
a = n*q + r
|r| < |n|
,但无法确定 r
的值。有两个答案,一个是负数,一个是正数。
n mod M == (n + M) mod M
而一般来说:
n mod M == (n + X * M) mod M
a/b
是可表示的,则表达式(a/b)*b + a%b
应等于a
。 - cafa = b*q + r
,就像将分数 a/b
四舍五入为整数商 q
,然后计算余数 r
一样。truncate(7/3) = 2
7 = 3*2 + 1
truncate(-7/3) = -2
-7 = 3* -2 - 1
truncate(7/-3) = -2
7 = -3* -2 + 1
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
math
中的.remainder()
。Python 3.7.0a0 (heads/master:f34c685020, May 8 2017, 15:35:30)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import math
>>> math.remainder(-1, 10)
-1.0
来自文档:
返回x除以y的IEEE 754风格余数。对于有限的x和有限的非零y,这是差值
x - n*y
,其中n是商x / y
的精确值最接近的整数。如果x / y
恰好处于两个连续整数之间,则使用最近的偶数整数作为n
。因此,余数r = remainder(x, y)
总是满足abs(r) <= 0.5 * abs(y)
。特殊情况遵循IEEE 754:特别是,对于任何有限x,
remainder(x, math.inf)
都是x,而remainder(x, 0)
和remainder(math.inf, x)
会针对任何非NaN x引发ValueError异常。如果余数操作的结果为零,则该零将与x具有相同的符号。在使用IEEE 754二进制浮点数的平台上,此操作的结果始终可以准确表示:不会引入舍入误差。