接受回答后
在 C 中,从 C99 开始,即使使用负操作数,结果%
也可以很好地定义。见下文。
在 C 中,%
运算符被命名为 C 中的“余数”而不是“模数”。
要执行欧几里得除法和余数,而不会产生截断、范围、double
转换问题**:
void Euclidean_divide_remainder(int a, int b, int *q, int *r) {
*q = a / b;
*r = a % b;
if (a < 0 && *r != 0) {
if (b < 0) { (*q)++; *r -= b; }
else { (*q)--; *r += b; }
}
}
void rtest(int a, int b) {
int eq, er;
Euclidean_divide_remainder(a, b, &eq, &er);
printf("f(%2d,%2d) / %2d %% %2d E/ %2d E%% %2d\n",
a, b, a / b, a % b, eq, er);
}
void rtest4(int a, int b) {
rtest(a, b);
rtest(a, -b);
rtest(-a, b);
rtest(-a, -b);
printf("\n");
}
int main(void) {
rtest4(7, 3);
return 0;
}
f( 7, 3) / 2 % 1 E/ 2 E% 1
f( 7,-3) / -2 % 1 E/ -2 E% 1
f(-7, 3) / -2 % -1 E/ -3 E% 2
f(-7,-3) / 2 % -1 E/ 3 E% 2
/ 运算符的结果是第一个操作数除以第二个操作数的商;% 运算符的结果是余数。在这两种操作中,如果第二个操作数的值为零,则行为未定义。C11dr §6.5.5 5
当整数被除法时, / 运算符的结果是代数商,其中任何小数部分被丢弃。(这通常称为“向零截断”。)如果商a/b
是可表示的,则表达式(a/b)*b + a%b
应等于a
; 否则,两者的行为a/b
和a%b
是未定义的。C11dr §6.5.5 6
** 例外情况:
的结果a%0
是未定义的。
对于 2 的补码,INT_MIN % -1
和INT_MIN E% -1
(在数学上应该是 0)是问题。这是由于INT_MIN / -1
(在数学上应该是INT_MAX + 1
)是一个问题,因为答案不适合该int
范围。