在一个C程序中,我尝试了以下操作(只是为了检查行为)
x = 5 % (-3);
y = (-5) % (3);
z = (-5) % (-3);
printf("%d ,%d ,%d", x, y, z);
在gcc中输出为(2,-2,-2)我以为每次都会有积极的结果。模量可以是负的吗?有人能解释一下这种行为吗?
在一个C程序中,我尝试了以下操作(只是为了检查行为)
x = 5 % (-3);
y = (-5) % (3);
z = (-5) % (-3);
printf("%d ,%d ,%d", x, y, z);
在gcc中输出为(2,-2,-2)我以为每次都会有积极的结果。模量可以是负的吗?有人能解释一下这种行为吗?
当前回答
根据C99标准,第6.5.5节 乘法运算符,需要以下条件:
(a / b) * b + a % b = a
结论
余数运算结果的符号 到C99,和红利是一样的。
让我们看一些例子(除数/除数):
只有股息是负的
(-3 / 2) * 2 + -3 % 2 = -3
(-3 / 2) * 2 = -2
(-3 % 2) must be -1
当只有除数为负时
(3 / -2) * -2 + 3 % -2 = 3
(3 / -2) * -2 = 2
(3 % -2) must be 1
除数和被除数都为负
(-3 / -2) * -2 + -3 % -2 = -3
(-3 / -2) * -2 = -2
(-3 % -2) must be -1
6.5.5 Multiplicative operators Syntax multiplicative-expression: cast-expression multiplicative-expression * cast-expression multiplicative-expression / cast-expression multiplicative-expression % cast-expression Constraints Each of the operands shall have arithmetic type. The operands of the % operator shall have integer type. Semantics The usual arithmetic conversions are performed on the operands. The result of the binary * operator is the product of the operands. The result of the / operator is the quotient from the division of the first operand by the second; the result of the % operator is the remainder. In both operations, if the value of the second operand is zero, the behavior is undefined. When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded [1]. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a. [1]: This is often called "truncation toward zero".
其他回答
在数学中,这些惯例的起源,没有断言模算术应该产生一个正的结果。
Eg.
1 mod 5 = 1,但也可以等于-4。也就是说,1/5从0得到余数1或从5得到余数-4。(都是5的因数)
同样的, -1 mod 5 = -1,它也可以等于4。也就是说,-1/5从0得到余数-1或从-5得到余数4。(都是5的因数)
要进一步阅读,请参阅数学中的等价类。
我认为没有必要检查数字是否为负。
求正模的一个简单函数是这个-
编辑:假设N > 0和N + N - 1 <= INT_MAX
int modulo(int x,int N){
return (x % N + N) %N;
}
这对x的正负都成立。
原始p.s.:也正如@chux指出的那样,如果你的x和N可能分别达到INT_MAX-1和INT_MAX,只需将int替换为long long int。
如果它们也越过了long long的限制(即在LLONG_MAX附近),那么你应该分别处理正的和负的情况,在这里的其他答案中描述。
模量可以是负的吗?
%可以是负数,因为它是余数运算符,是除法后的余数,而不是欧几里得除法后的余数。由于C99的结果可能是0,负或正。
// a % b
7 % 3 --> 1
7 % -3 --> 1
-7 % 3 --> -1
-7 % -3 --> -1
要的模OP是一个经典的欧几里得模,而不是%。
我以为每次都会有积极的结果。
要执行定义良好的欧几里得模,只要a/b有定义,a,b是任意符号,且结果永远不为负:
int modulo_Euclidean(int a, int b) {
int m = a % b;
if (m < 0) {
// m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
m = (b < 0) ? m - b : m + b;
}
return m;
}
modulo_Euclidean( 7, 3) --> 1
modulo_Euclidean( 7, -3) --> 1
modulo_Euclidean(-7, 3) --> 2
modulo_Euclidean(-7, -3) --> 2
其他答案已经在C99或更高版本中解释过,涉及负操作数的整数除法总是截断为零。
注意,在C89中,结果向上舍入还是向下舍入是由实现定义的。因为(a/b) * b + a%b在所有标准中都等于a,包含负操作数的%的结果也是在C89中实现定义的。
模运算的结果取决于分子的符号,因此y和z都是-2
这是参考资料
http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_14.html
整数的除法 介绍整数除法的函数。 这些函数在GNU C库中是多余的,因为在GNU C中 '/'运算符总是四舍五入到零。但是在其他C中 实现中,'/'可以用不同的负参数四舍五入。 Div和ldiv很有用,因为它们指定了如何舍入 商:趋于零。余数的符号和 分子。