是否存在与潜在溢出相乘的问题,然后通过除法进行验证?

时间:2015-08-31 12:08:26

标签: c++ c numbers overflow multiplication

假设我有两个size_t变量,我需要将它们相乘并得到size_t的结果。

size_t first = ...;
size_t second = ...;
size_t result = first * second;

他们可能会溢出,所以我需要检查一下。

“干净”的方法是首先检查乘法是否可以使用除法:

if( second != 0 && first > ((size_t)-1) / second ) {
   //handle overflow
}
//proceed with computing first * second

看似不那么“干净”的方法是首先乘以然后用除法检查结果:

size_t result = first * second;
if( second != 0 && result / second != first )
   //handle overflow
}

然而,因为无符号数字乘以“安全溢出”,包裹在零附近,这样就可以了,看起来就像以前的代码(首先检查,然后相乘)。

第二个代码是否存在任何潜在问题?它会永远和第一个一样好吗?

3 个答案:

答案 0 :(得分:1)

从数学POV, if

Environment.Exit

对于某些溢出值是正确的(这意味着a和b都不是0),那么这是一个问题 根据{{​​3}},对于溢出来说永远不会这样,因为得到一个结果,比特长度为
结果变量n必须大于a * b(((a*b) mod (2^n)) / b == a )所需的位长。

代码方面,我现在也无法想到任何问题。

答案 1 :(得分:1)

我会说你不仅需要检查分区,还要检查余数:

if( second != 0 && (result / second != first || (result % second) != 0))

如果c = b * a,那么c只有一个值,例如c / b = a。试图将任何其他值除以b将不会产生。

然而,这不是整数数学,而是真正的数学。由于整数除法四舍五入,公式在技术上不会成立,因为,如果b至少为2,(c + 1)/ b对于某些c值也是a。

答案 2 :(得分:0)

您指出的第一种方法是definitelly不正确。如上所述,将负数转换为无符号类型是不正确的,并处理未定义的行为。

第二种方法,作为产品与两个因素的乘法不同的唯一方法是在中间出现溢出,这是正确的,但同样,溢出可以处理未定义的行为,因此,将是不正确的(您隐含地认为溢出将来自乘法模运算,并且结果确实未定义)。

检查可能溢出的一种方法可能是:

SELECT ts.tid, ts.startdate, ts.enddate, ts.status,
  t1.test_status Test1,
  t2.test_status Test2,
  t3.test_status Test3
 FROM transaction ts
  JOIN test_details t1 ON (t1.tid=ts.tid AND t1.test_name='Test1')
  JOIN test_details t2 ON (t2.tid=ts.tid AND t2.test_name='Test2')
  JOIN test_details t3 ON (t3.tid=ts.tid AND t3.test_name='Test3');

这是完全定义的,允许您在以便携方式进行实际乘法之前检测溢出。