22

我有两个数字:AB。我需要A+B在我的代码中的某个地方进行计算。两者都是A,它们可以是正面的或负面的。Blong long

我的代码运行错误,我怀疑在计算A+B. 我只是想检查是否A+B超出long long范围。所以,任何方法都是可以接受的,因为我只用它来调试。

4

4 回答 4

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 上,编译器也可能假设没有发生未定义的行为,并在实现时完全删除溢出检查。因此,对该问题的评论中建议的检查非常不可靠。

于 2013-04-10T08:31:57.107 回答
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;

我们可以这样推理:

  • 如果AB是相反的符号,它们就不能溢出——大于零的一个需要大于max或小于零的一个需要小于min

  • 在其他情况下,简单的代数就足够了。A + B > max => B > max - A如果它们都是正面的,则会溢出。否则,如果它们都是负数,A + B < min => B < min - A

于 2013-04-10T08:35:28.557 回答
3

此外,如果您仅将其用于调试,则可以使用以下“hack”直接从最后一个操作中读取溢出位(假设您的编译器/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
    ...
于 2013-04-10T08:48:25.470 回答
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)));
}
于 2013-04-10T08:51:45.007 回答