假设我有两个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
}
然而,因为无符号数字乘以“安全溢出”,包裹在零附近,这样就可以了,看起来就像以前的代码(首先检查,然后相乘)。
第二个代码是否存在任何潜在问题?它会永远和第一个一样好吗?
答案 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');
这是完全定义的,允许您在以便携方式进行实际乘法之前检测溢出。