有符号整数的加减运算,溢出判断

为了简化,以8位二进制有符号整数为例。

1、原码、反码、补码的基础知识

原码:
         口口口口 口口口口  //最高位是符号位,0表示正数,1表示负数
         所以表示的范围是-128~127(其中-128是用1000 0000表示)
反码:
         正数的反码是其原码;
         负数的反码是其原码的符号位不变,其它为按位取反。
补码:
         正数的补码是其原码;
         负数的补码是其反码加1。

1)为了解决计算机中的减法运算,提出了“补码”概念。“反码”只是从原码求补码过程的一个产物。
2)因此,计算机中数的存储是按补码进行的。(正数也是,因为三个码一样的)
3)从原码能快速看出具体数值是多少。若给出负数的16进制反码和补码,习惯是把它转成原码看。
4)负数的原码转补码口诀,对其绝对值按位取反再加1(有人也有这种说法,除了符号位按位取反再加1)。

【例子】求-2补码.
-2=0-2=(0xff+1)-2=0xff-2+1,即对2按位取反再加1。

5)负数的原码和补码的快速转换。利用满周期归0的思想,就不需在草稿纸上逐位求反加1这么费力得计算。

【例子】求-2的补码(假设以int类型变量保存).
因为2+(-2)=0,由int的表示范围也知道2+(0xffff fffe)=0,故-2的补码是0xffff fffe

2、加法和减法运算

加法运算:

    (假设a和b都是正整数)
   a+b  
   1)8位都按位相加
   2)正数相加使符号位变1,表示溢出,结果为负数。
       【例1】96+64=0110 0000 +0100 0000=1010 0000
      注意上述得到的是计算机存储的值,对于负数它就是补码。那么它的反码是补码减1,即1001 1111;它的原码是反码除了符号位按位取反,
      即1110 0000,是-96。

减法运算:

    (假设a和b都是正整数)
   a-b=a+(-b) =a+(0-b)=a+(0xFF+1-b)=a+(0xFF-b+1)
 1)对正整数b的原码按位取反再加1,即对负整数-b除了符号位外按位取反再加1。 然后再和a相加。      
 2)正数和负数相加不会有溢出现象。   
 3)如果是求-a-b,其实可以转换为0-a-b分两次求出,也等于-a的补码和-b的补码相加。负数相加若溢出,结果为正数。
    【例2】-80-64=(-80)+(-64)=1011 0000 +1100 0000=0111 0000=0011 00
   同理,上边得到的是计算机存储的值。因为是正数,直接看出等于112。
    【例3】-16-64=(-80)+(-64)=1111 0000 +1100 0000=1011 0000
   同理,上边得到的是计算机存储的值,对于负数它就是补码。那么它的反码是补码减1,即1010 1111;它的原码是反码除了符号位按位取反,
   即1101 0000,即-80。

3、程序测试

【例1】正数相加溢出
void main()
{
    char i = 96+64;
    printf("%d\n", (char)i);
    printf("0x%x\n", (char)i);

}

执行结果:
这里写图片描述
分析:
1) 对于unsigned char 8位符号整数,在VS2015上通过printf(“%x”,a);输出显示,个人觉得因为是负数(最高位符号为1),所以要隐含转换为长度32位的类型,所以才有0xffff ffa0。
2)不过没关系,因为它还是补码,对应的反码是补码减1,即0xffff ff9f; 对应的原码是反码除了符号位位取反,即0x8000 0060,依然是-96。

【例2】负数相加溢出
void main()
{
    char i = -80-64;
    printf("%d\n", (char)i);
    printf("0x%x\n", (char)i);

}

执行结果:
这里写图片描述
分析:
1) 对于unsigned char 8位符号整数,在VS2015上通过printf(“%x”,a);输出显示,因为符号为正(是0),只有最低8位是有效的,所以才显示8位,得到0x70,即112。

【例3】负数相加未溢出
void main()
{
    char i = -16-64;
    printf("%d\n", (char)i);
    printf("0x%x\n", (char)i);

}

执行结果:
这里写图片描述
分析:
1) 对于unsigned char 8位符号整数,在VS2015上通过printf(“%x”,a);输出显示,个人觉得是负数(最高位符号为1),所以要隐含转换为长度32位的类型,所以才有0xffff ffb0。
2)不过没关系,因为它还是补码,对应的反码是补码减1,即0xffff ffaf; 对应的原码是反码除了符号位位取反,是0x8000 0050,即-80。

  • 12
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值