PAT甲级1065 A+B and C (64bit) 详细版

原题链接1065 A+B and C (64bit)
无论是在pat还是在leetcode中,总是特别喜欢出一些数据取到类型边界的问题。这都涉及到计算机组成原理中的数据在计算机中存放问题。现以PAT甲级1065题为出发点总结如下。
众所周知,数据在计算机中是以二进制补码的形式存放的。其中有符号数的最高位解释为符号位,无符号数的最高位仍未数据位。
以64位的long long为例,一个long long类型的整数在计算机中占据64bit,即8B(字节)。并且最高位即第63位(从0开始)为符号位,取值范围为[-2 ^ 63, 2 ^ 63 - 1],64位补码可以比原码多表示一个数,即-2^63,原码最小只能表示到-2 ^ 63 +1。
记住特殊的几个long long型数据的二进制形式:

十进制下的-1表示为64位的二进制为1…1共64个1
十进制下的2^63 - 1表示为64位的二进制为 01…1共63个1
十进制下的 -2^63表示为64位的二进制为10…0共63个0

当两个long long类型的数据进行相加时,有可能结果超出long long类型的存储范围而发生溢出,包括正溢与下溢。

上溢

a为正数,b为正数,但是a+b超过了long long 的最大的范围 2 ^ 63 - 1,即a+b>2 ^ 63 - 1。
分两种情况
1、和恰好超过了long long 的最大值
a = 1,b = 2 ^ 63 - 1,此时a + b =2 ^ 63 ,是恰好超出了long long的最大取值范围。
a的二进制为0…01B,共63个0,即十六进制的0x0000000000000001。
b的二进制为01…1B,共63个1,即十六进制的0x7FFFFFFFFFFFFFFF。
按照二进制补码相加的原则此时a+b为0x8000000000000000,即为十进制的-2 ^ 63。
2、a = 2 ^ 63 - 1,b= 2 ^ 63 - 1,此时a + b = 2 ^ 64 -2,肯定也是已经超过了long long 的最大正数取值范围了。
a与b的二进制都是01…1B,共63个1,即十六进制的0x7FFFFFFFFFFFFFFF。
此时按照二进制补码相加的原则a + b = 0xFFFFFFFFFFFFFFFE,该数加上1恰好为0xFFFFFFFFFFFFFFFF,即十进制的-1,所以该数为-2。

==故上溢时,有-2 ^ 63 =< a + b < = -2,即a + b 小于0 ==
综上,当上溢时,会有a>0&&b>0&&a+b<0

下溢

a为负数,b为负数,但是a + b 超过了long long 的最小范围 - 2 ^ 63。
同样分为两种情况。
1、a = -1,b = - 2 ^ 63。
a的二进制为1…1B,共64个1,即十六进制的0xFFFFFFFFFFFFFFFF。
b的二进制为10…0B,共63个0,即十六进制的0x8000000000000000。
按照二进制补码加法的原则,此时a + b = 0x7FFFFFFFFFFFFFFF,即为十进制的 2 ^ 63 -1。
2、a = - 2 ^ 63,b = - 2 ^ 63。
此时a 和b的二进制都是10…0B,共63个0,即十六进制的0x8000000000000000。
按照二进制补码相加的原则,a + b = 0x0000000000000000,即为十进制的0。
故下溢时会有 0 < = a + b <= 2 ^ 63 -1
综上,当下溢发生时,有a<0&&b<0&&a+b>=0。
所以原题的代码便为

#include <iostream>

using namespace std;

int main()
{
    
    
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
    
    
        long long a,b,c;
        scanf("%lld%lld%lld",&a,&b,&c);
        long long sum = a + b;
        if(a > 0 && b > 0 && sum < 0)
            printf("Case #%d: true\n",i);
        else if(a < 0 && b < 0 && sum >= 0)//注意是 >= 0
            printf("Case #%d: false\n",i);
        else printf("Case #%d: %s\n",i,sum>c?"true":"false");
    }
    return 0;
}

这在计算机组成中只是最简单的补码运算,复杂的有乘法和除法,以及浮点数运算,只不过当与数据结构相结合时,边界条件确实是容易使人犯错。

猜你喜欢

转载自blog.csdn.net/weixin_44321570/article/details/113899122