有符號整數的加減運算,溢出判斷

爲了簡化,以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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章