其他人的回答很好地解释了 OP 在将负值转换为操作之前没有产生预期结果时遇到了unsigned
麻烦%
。
以下是解决方案:一个求助于更广泛的数学(可能并不总是可用)。第二个是精心构造的,以避免任何未定义的行为、(UB)、实现定义的(ID)行为或仅使用int, unsigned
数学的溢出。它不依赖于 2 的补码。
unsigned int mod_ref(int x, unsigned int m) {
long long r = ((long long) x) % m;
return (unsigned) (r >= 0 ? r : r + m);
}
unsigned int mod_c(int x, unsigned int m) {
if (x >= 0) {
return ((unsigned) x) % m;
}
unsigned negx_m1 = (unsigned) (-(x + 1));
return m - 1 - negx_m1 % m;
}
一名试驾员
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
void testm(int x, unsigned int m) {
if (m) {
unsigned r0 = mod_ref(x, m);
unsigned r1 = mod_c(x, m);
if (r0 != r1) {
printf("%11d %10u --> %10u %10u\n", x, m, r0, r1);
}
}
}
int main() {
int ti[] = {INT_MIN, INT_MIN + 1, INT_MIN / 2, -2, -1, 0, 1, 2, INT_MAX / 2,
INT_MAX - 1, INT_MAX};
unsigned tu[] = {0, 1, 2, UINT_MAX / 2, UINT_MAX - 1, UINT_MAX};
for (unsigned i = 0; i < sizeof ti / sizeof *ti; i++) {
for (unsigned u = 0; u < sizeof tu / sizeof *tu; u++) {
testm(ti[i], tu[u]);
}
}
for (unsigned i = 0; i < 1000u * 1000; i++) {
int x = rand() % 100000000;
if (rand() & 1)
x = -x - 1;
unsigned m = (unsigned) rand();
if (rand() & 1)
m += INT_MAX + 1u;
testm(x, m);
}
puts("done");
return 0;
}