当有人在C程序中输入负数时,有人可以帮我弄清楚为什么这个程序给出模数运算的错误答案?
我很确定导致问题的原因是scanf
功能。使用正整数时会给出正确的答案。
代码如下:
#include <stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int answer = 0;
puts("enter two number to find the modulus of...");
if (scanf("%3d %3d",&num1,&num2) != 2)
puts("something went wrong");
else {
answer = (num1 % num2);
printf("the modulus of %d and %d is: %d\n", num1, num2, answer);
}
}
答案 0 :(得分:4)
在ANSI C中,未对负输入定义模数运算符的结果符号。您可以从数学库(ref)尝试div()
。它返回一个带有商和余数的结构,它对负输入可靠地工作。
或者,正如Alexey Frunze所说,你可以启用C99模式。我懒得查看标准,但稍微测试(gcc -std=c99
)表明结果的符号与左操作数的符号相符。因此,如果您想要ANSI兼容性,div()
仍然是最佳的。
或者,您可以完全控制情况。但你必须选择正确的含义。以下内容来自Wikipedia。
int x, y, q, r; // all snippets: left-arg, right-arg, quotient, remainder
q = trunc( (double)x / y);
r = x - y * q;
q = floor( (double)x / y);
r = x - y * q;
q = y > 0 ? floor( (double)x / y) : ceiling( (double)x / y);
r = x - y * q;
答案 1 :(得分:2)
接受回答后
在C中,自C99起,即使使用负操作数,%
的结果仍然是井。见下文。
在C中,%
运算符在C中被命名为“余数”而不是“模数”。
执行欧几里德分部&amp;余数没有发生截断,范围,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.55
当整数被分割时,/运算符的结果是任何代数商 分数部分丢弃。 (这通常称为“截断为零”。)如果商
a/b
可表示,则表达式(a/b)*b + a%b
应等于a
;否则,a/b
和a%b
的行为都是未定义的。 C11dr§6.5.56
**例外:
a%0
的结果未定义。
对于2的补码,INT_MIN % -1
和INT_MIN E% -1
(数学上应该为0)是问题。这是由INT_MIN / -1
(数学上应该INT_MAX + 1
)引起的问题,因为答案不适合int
范围。