如何在乘以两个2的补码整数时检测溢出?

时间:2010-04-26 13:53:16

标签: algorithm overflow integer-overflow twos-complement

我想将两个数相乘,并检测是否有溢出。最简单的方法是什么?

6 个答案:

答案 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_VALUEInteger.MIN_VALUE进行比较(取决于符号组合),然后再将结果转换为到int

如果类型已经是最大的,那么检查一个是否小于最大值除以另一个。但是不要拿绝对值!相反,你需要为每个符号组合使用单独的比较逻辑neg neg,pos pos和pos neg(neg pos显然可以简化为pos neg和pos pos可能会减少为neg * neg)。首先测试0个参数以允许安全划分。

对于实际代码,请参阅公共数学2的MathUtils类的Java源代码,或ArithmeticUtilscommons-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,但它已经完成并处理了我所知道的所有案例。