C 和 Python - 模 (%) 运算的不同行为
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1907565/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C and Python - different behaviour of the modulo (%) operation
提问by psihodelia
I have found that the same mod operation produces different results depending on what language is being used.
我发现相同的 mod 操作会根据使用的语言产生不同的结果。
In Python:
在 Python 中:
-1 % 10
produces 9
产生9
In C it produces -1!
在 C 中它产生-1!
- Which one is the right modulo?
- How to make mod operation in C to be the same like in Python?
- 哪个是正确的模数?
- 如何使 C 中的 mod 操作与 Python 中的相同?
回答by Alex B
- Both variants are correct, however in mathematics (number theory in particular), Python's modulois most commonly used.
- In C, you do
((n % M) + M) % M
to get the same result as in Python. E. g.((-1 % 10) + 10) % 10
. Note, how it still works for positive integers:((17 % 10) + 10) % 10 == 17 % 10
, as well as for both variants of C implementations (positive or negative remainder).
- 两种变体都是正确的,但是在数学(特别是数论)中,Python 的模是最常用的。
- 在 C 中,您
((n % M) + M) % M
可以得到与 Python 中相同的结果。例如((-1 % 10) + 10) % 10
. 请注意,它仍然适用于正整数:((17 % 10) + 10) % 10 == 17 % 10
,以及 C 实现的两种变体(正余数或负余数)。
回答by fortran
Python has a "true" modulo operation, while C has a remainderoperation.
Python 有一个“真”模运算,而 C 有一个余数运算。
It has a direct relation with how the negative integer division is handled, i.e. rounded towards 0 or minus infinite. Python rounds towards minus infinite and C(99) towards 0, but in both languages (n/m)*m + n%m == n
, so the % operator must compensate in the correct direction.
它与负整数除法的处理方式有直接关系,即向 0 或负无穷大舍入。Python 向负无穷大舍入,C(99) 向 0 舍入,但在两种语言中(n/m)*m + n%m == n
,因此 % 运算符必须在正确的方向上进行补偿。
Ada is more explicit and has both, as mod
and rem
.
Ada 更明确,同时具有 asmod
和rem
。
回答by AnT
In C89/90 the behavior of division operator and remainder operator with negative operands is implementation-defined, meaning that depending on the implementation you can get either behavior. It is just required that the operators agree with each other: from a / b = q
and a % b = r
follows a = b * q + r
. Use static asserts in your code to check the behavior, if it relies critically on the result.
在 C89/90 中,带有负操作数的除法运算符和余数运算符的行为是实现定义的,这意味着根据实现,您可以获得任一行为。只需要操作符彼此同意: froma / b = q
和a % b = r
follow a = b * q + r
。如果行为严重依赖结果,请在代码中使用静态断言来检查行为。
In C99 the behavior you observe has become standard.
在 C99 中,您观察到的行为已成为标准。
In fact, either behaviors have certain logic in it. The Python's behavior implements the true modulo operation. The behavior you observed is C is consistent with rounding towards 0 (it's also Fortran behavior).
其实,这两种行为都有其一定的逻辑性。Python 的行为实现了真正的模运算。您观察到的行为是 C 与向 0 舍入一致(这也是 Fortran 行为)。
One of the reasons the rounding towards 0 is preferred in C is that it is rather natural to expect the result of -a / b
be the same as -(a / b)
. In case of true modulo behavior, -1 % 10
would evaluate to 9, meaning that -1 / 10
has to be -1. This might be seen as rather unnatural, since -(1 / 10)
is 0.
在 C 中首选向 0 舍入的原因之一是期望结果-a / b
与 相同是相当自然的-(a / b)
。在真正的模行为的情况下,-1 % 10
将评估为 9,这意味着-1 / 10
必须为 -1。这可能会被视为相当不自然,因为它-(1 / 10)
是 0。
回答by Brian R. Bondy
Both answers are correct since -1 modulo 10
is the same as 9 modulo 10
.
两个答案都是正确的,因为-1 modulo 10
与9 modulo 10
.
r = (a mod m)
a = n*q + r
You can be sure that |r| < |n|
, but not what the value of r
is. There are 2 answers, negative and positive.
您可以确定|r| < |n|
,但不确定 的值r
是什么。有2个答案,否定的和肯定的。
In C89, although the answer will always be correct, the exact value of a modulo operation (they refer to it as remainder) is undefined, meaning it can be either a negative result or a positive result. In C99 the result is defined.
在 C89 中,虽然答案总是正确的,但模运算的确切值(他们将其称为余数)是不确定的,这意味着它可以是负结果或正结果。在 C99 中定义了结果。
If you want the positive answer though, you can simply add 10 if you find your answer is negative.
如果你想要肯定的答案,如果你发现你的答案是否定的,你可以简单地加 10。
To get the modulo operator to work the same on all languages, just remember that:
要使模运算符在所有语言上都相同,请记住:
n mod M == (n + M) mod M
and in general:
一般来说:
n mod M == (n + X * M) mod M
回答by aka.nice
Performing Euclidean division a = b*q + r
, is like rounding the fraction a/b
to an integer quotient q
, and then compute the remainder r
.
执行欧几里德除法a = b*q + r
,就像将分数四舍五入为a/b
整数商q
,然后计算余数r
。
The different results you see depends on the convention used for rounding the quotient...
您看到的不同结果取决于用于四舍五入商数的约定......
If you round toward zero (truncate), you will get a symmetry around zero like in C:
如果向零四舍五入(截断),您将像在 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
If you round toward negative infinity (floor), you will get a remainder like in Python:
如果你向负无穷大(下限)四舍五入,你会得到像 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
If you round to nearest int (tie to whatever you want, to even, or away from zero) you'll get a centered modulo:
如果您四舍五入到最近的 int(与您想要的任何东西、偶数或远离零相联系),您将得到一个居中的模数:
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
You could try to implement your own modulo with rounding toward positive infinity (ceil), and you would inventa rather unconventional modulo, but it would still be kind of modulo...
您可以尝试实现自己的模数,并朝正无穷大 (ceil) 取整,并且您会发明一个非常规的模数,但它仍然是一种模数......
回答by vishes_shell
Since python 3.7 you can also use .remainder()
from math
built-in module.
因为Python 3.7,你也可以使用.remainder()
从math
内置模块。
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
From docs:
从文档:
Return the IEEE 754-style remainder of x with respect to y. For finite x and finite nonzero y, this is the difference
x - n*y
, where n is the closest integer to the exact value of the quotientx / y
. Ifx / y
is exactly halfway between two consecutive integers, the nearest even integer is used forn
. The remainderr = remainder(x, y)
thus always satisfiesabs(r) <= 0.5 * abs(y)
.Special cases follow IEEE 754: in particular,
remainder(x, math.inf)
is x for any finite x, andremainder(x, 0)
andremainder(math.inf, x)
raise ValueError for any non-NaN x. If the result of the remainder operation is zero, that zero will have the same sign as x.On platforms using IEEE 754 binary floating-point, the result of this operation is always exactly representable: no rounding error is introduced.
返回 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:尤其
remainder(x, math.inf)
是对于任何有限X X和remainder(x, 0)
和remainder(math.inf, x)
提高ValueError异常任何非NaN的X。如果余数运算的结果为零,则该零的符号与 x 相同。在使用 IEEE 754 二进制浮点数的平台上,此操作的结果始终可以精确表示:不引入舍入误差。