我有两个号码:A
和B
。我需要在代码中的某处计算A+B
。 A
和B
都是long long
,它们可以是正面或负面。
我的代码运行错误,我怀疑在计算A+B
时会出现问题。我只是想检查A+B
是否超过long long
范围。所以,任何方法都是可以接受的,因为我只将它用于调试。
答案 0 :(得分:31)
仅当两个数字具有相同符号时才可能溢出。如果两者都是正数,那么如果数学A + B > LLONG_MAX
或等效B > LLONG_MAX - A
,则会出现溢出。由于右侧是非负的,后一种情况已经暗示B > 0
。类似的论点表明,对于否定的情况,我们也不需要检查B
的符号(感谢Ben Voigt指出B
上的符号检查是不必要的)。然后你可以检查
if (A > 0) {
return B > (LLONG_MAX - A);
}
if (A < 0) {
return B < (LLONG_MIN - A);
}
return false;
检测溢出。由于初始检查,这些计算不会溢出。
检查A + B
结果的符号将有效保证溢出整数计算的环绕语义。但是有符号整数的溢出是未定义的行为,即使在环绕是实现行为的CPU上,编译器也可能认为没有发生未定义的行为,因此在实现时完全删除溢出检查。因此,对问题的评论中建议的检查非常不可靠。
答案 1 :(得分:7)
如下所示:
long long max = std::numeric_limits<long long>::max();
long long min = std::numeric_limits<long long>::min();
if(A < 0 && B < 0)
return B < min - A;
if(A > 0 && B > 0)
return B > max - A;
return false;
我们可以解释如下:
如果A
和B
符号相反,则它们不会溢出 - 大于零的那个需要大于max
或者小于零的那个需要溢出小于min
。
在其他情况下,简单的代数就足够了。 A + B > max => B > max - A
如果两者都是正面的话会溢出。否则,如果它们都是否定的,A + B < min => B < min - A
。
答案 2 :(得分:2)
此外,如果您仅将其用于调试,则可以使用以下“黑客”功能。直接读取上一个操作的溢出位(假设你的编译器/ cpu支持这个):
int flags;
_asm {
pushf // push flag register on the stack
pop flags // read the value from the stack
}
if (flags & 0x0800) // bit 11 - overflow
...
答案 3 :(得分:2)
屏蔽符号,转换为无符号值,然后执行添加。如果它高于1 << (sizeof(int) * 8 - 1)
那么你就会溢出。
int x, y;
if (sign(x) == sign(y)){
unsigned int ux = abs(x), uy = abs(y);
overflow = ux + uy >= (1 << (sizeof(int) * 8 - 1));
}
更好的是,让我们写一个模板:
template <typename T>
bool overflow(signed T x, signed T y){
unsigned T ux = x, uy = y;
return ( sign(x) == sign(y) && (ux + uy >= (1 << (sizeof(T) * 8 - 1)));
}