我想将两个数相乘,并检测是否有溢出。最简单的方法是什么?
答案 0 :(得分:11)
答案 1 :(得分:3)
检查一个是否小于最大值除以另一个。 (所有值都是绝对的)。
2的补数几乎与它没有任何关系,因为如果x *(2 n - x)> 2 M ,则乘法溢出,这等于( x * 2 n -x 2 )> 2 M ,或x 2 < (x * 2 n - 2 M ),所以你必须比较溢出的数字(x 2 可能溢出,而结果可能不是)。
答案 2 :(得分:1)
如果您的号码不是来自最大的积分数据类型,那么您可能只是将它们加起来,乘以并与该数字的原始类型的最大值进行比较。例如。在Java中,当将两个int
相乘时,您可以将它们转换为long
并将结果与Integer.MAX_VALUE
或Integer.MIN_VALUE
进行比较(取决于符号组合),然后再将结果转换为到int
。
如果类型已经是最大的,那么检查一个是否小于最大值除以另一个。但是不要拿绝对值!相反,你需要为每个符号组合使用单独的比较逻辑neg neg,pos pos和pos neg(neg pos显然可以简化为pos neg和pos pos可能会减少为neg * neg)。首先测试0个参数以允许安全划分。
对于实际代码,请参阅公共数学2的MathUtils
类的Java源代码,或ArithmeticUtils
的commons-math 3。寻找public static long mulAndCheck(long a, long b)
。 正面 a和b的情况是
// check for positive overflow with positive a, positive b
if (a <= Long.MAX_VALUE / b) {
ret = a * b;
} else {
throw new ArithmeticException(msg);
}
答案 3 :(得分:0)
Pavel Shved的解决方案的替代品......
如果您选择的语言是汇编程序,那么您应该能够检查溢出标志。如果没有,您可以编写一个自定义汇编程序例程,如果设置了溢出标志,则设置变量。
如果这是不可接受的,您可以找到两个值(绝对值)中最重要的设置位。如果总和超过整数(或无符号)中的位数,那么如果它们相乘则会出现溢出。
希望这有帮助。
答案 4 :(得分:0)
在C中,这里有一些成熟优化的代码可以处理各种极端情况:
int
would_mul_exceed_int(int a, int b) {
int product_bits;
if (a == 0 || b == 0 || a == 1 || b == 1) return (0); /* always okay */
if (a == INT_MIN || b == INT_MIN) return (1); /* always underflow */
a = ABS(a);
b = ABS(b);
product_bits = significant_bits_uint((unsigned)a);
product_bits += significant_bits_uint((unsigned)b);
if (product_bits == BITS(int)) { /* cases where the more expensive test is required */
return (a > INT_MAX / b); /* remember that IDIV and similar are very slow (dozens - hundreds of cycles) compared to bit shifts, adds */
}
return (product_bits > BITS(int));
}
Full example with test cases here
上述方法的好处是它不需要转换为更大的类型,因此该方法可以适用于更大的整数类型。
答案 5 :(得分:0)
我想将两个(2的补码)相乘,并检测是否有溢出。最简单的方法是什么?
各种语言在发生之后没有指定溢出的有效检查,因此需要进行先前的测试。
对于某些类型,可能不存在更宽的整数类型,因此一般解决方案应将其自身限制为单个类型。
以下(Ref)仅需要对整数范围进行比较和已知限制。如果产品溢出,则返回1
,否则返回0
。
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
}
这是最简单的方法吗? IDK,但它已经完成并处理了我所知道的所有案例。