tmult_ok(x, y) 在int p = x*y; 溢出的任何时候都会失败,因为这是未定义的行为 (UB)。
出于同样的原因,它也会像tmult_ok(INT_MIN, -1) 这样的极端情况失败。
它不能便携地“工作”。
不依赖于 2 的补码的替代方案(和 others for /,-,+)。请注意,这将返回 tmult_ok() 的反面。
int is_undefined_mult1(int a, int b) {
if (a > 0) {
if (b > 0) {
return a > INT_MAX / b; // a positive, b positive
}
return b < INT_MIN / a; // a positive, b not positive
}
if (b > 0) {
return a < INT_MIN / b; // a not positive, b positive
}
return a != 0 && b < INT_MAX / a; // a not positive, b not positive
}
发生溢出时如何确保 p != x*y?
可移植代码不能。使用 C 中的有符号整数数学,溢出是 UB。代码应该在不首先执行乘法的情况下检测潜在的溢出。 @Quentin@Eugene Sh.
如何在所有情况下证明其正确性?
使用 2 倍宽的数学形成参考测试。如果 int 是 32 位,则将 tmult_ok() 与使用 64 位数学的乘法进行比较,并查看乘积是否在范围内。 @rici
int tmult_ok_ll(int x, int y) {
long long prod = x;
prod *= y;
return (prod >= INT_MIN && prod <= INT_MAX);
}
尝试所有组合是一种蛮力方法 - 对于 32 位 int 来说可能太长了。
尝试所有组合的子集,对于每个x,y,尝试INT_MIN, INT_MIN-1, INT_MIN-2, -2,-1, 0, 1, 2, , INT_MAX-1, INT_MAX。 (10*10 次测试)
也是所有组合的子集,对于每个值 +/- 在 sqrt(INT_MAX) 的 2 以内。 (10*10 次测试)
int 范围内的几百万个随机值也是谨慎的。
这可能还不够,但如果代码通过了这个,那么剩下的极端情况就很少了——这非常依赖于您的源代码。
另见@Eric Postpischil