二進制的補碼


今天在學習C Primer Plus(第五版)中文版.pdf的時候遇到這么個問題,先上代碼:

#include <stdio.h>
#define PAGES 336
#define WORDS 65618
int main(void)
{
        short num = PAGES;
        short mnum = -PAGES;

        printf("num as short and unsigned short:%hd %hu\n",num,num);
        printf("-num as short and unsigned short:%hd %hu\n",mnum,mnum);
        printf("num as int and char:%d %c\n",num,num);
        printf("WORDS as int,short,and char:%d %hd %c\n",WORDS,WORDS,WORDS);return 0;
}

結果:

num as short and unsigned short:336 336
-num as short and unsigned short:-336 65200
num as int and char:336 P
WORDS as int,short,and char:65618 82 R

請看我標紅的部分,其實我蠻想不明白的,為什么-336的無符號整數是65200呢?書上說是2的補碼(書中描述):數字0到32767代表它們本身,而數字32768到65535則代表負數,65535代表-1,65534代表-2,依次類推,因此-336由65536-336,也即65200來表示;本寶寶表示真心沒看懂啥意思,然后就在網上各種找二進制的補碼是啥意思,下面咱們就來看看什么是二進制的補碼

我試驗的計算及環境假設是8位的,那接下來我就拿計算機是8位作基礎來講解:

一、負數在計算機中如何表示

  之前我寫了一篇博客,里面是計算c語言整數類型的取值范圍的額,二進制中區分正負數的方法是看二進制的最高位是0還是1,1為負數,0為正數

  比如:127的二進制是01111111,而-127的二進制是 10000001(011111111 - 先取反,再加1 ->10000000+1 = 10000001),從這里可以看出127的最高位是0,而-127的最高位是1

二、什么是二進制補碼

  取一個數的二進制補碼需要兩步:

  1>.每個二進制位都取相反的值,也就是二進制位是1的,補碼就是0,二進制位是0的,補碼就是1

  2>.再把取反的二進制數轉換成十進制,加上1,最后的結果就是這個數的補碼的十進制數

  舉例:取-127的二進制補碼(8位機)

    二進制數:01111111

    補碼:10000000

    結果:補碼 10000000 + 1 = 10000001(129)

    也就是說-127在計算機(8位機)中10000001(寫到這里,我突然有點明白C Primer Plus書中描述的啥意思:0-127代表它本身,128-255代表負數,那-127就等於256-127=129

  那可能很多人會說:為什么是這樣啊?雖然知道怎么計算了,但是不知道為什么是這么計算的,那么接下來就來說說二進制補碼的原理

三、二進制補碼的原理

  那大家都知道負數怎么來的,比如:A-B,那A比B小,結果就會是負數,這就有很多情況了,咱不討論,就比如給你一個負數,那么最直接的你肯定會想到一個表達式了,比如給你個-127,那表達式就是0-127的來的,那我們把他轉換成二進制來運算一下:

  預想結果:-127

  十進制表達式:0-127

  二進制表達式:00000000(0) - 01111111(127)

  以前小學數學當被減數大於減數的時候都要向上借一位來減的,那么接下來就是借位(

  重點:這里計算的時候二進制的位數是有規定的,比如-127,它是1111111 由7個1的二進制,那同學就用7個0的二進制去減,結果借一位變成了10000000(128)-1111111(127) = 1,然后在加1等於2,結果-127的補碼就是00000010(2),這樣可是錯的,一定要遵守一個標准,那就是當前計算機是多少位的就借多少位加1位,那么比如-10是1010,就是00001010,借位就得在第9位上借,也就是100000000,結果就是246(11110110)

  借位進行運算:

    1>.100000000(256) - 01111111(127) = 10000001(129)

    2>.100000000(256) = 11111111(255) + 1;

      11111111(255) - 01111111(127) = 10000000(128)

      10000000(128) + 1 = 10000001(129)

  上面就是二進制補碼的簡單計算過程

四、二進制補碼有哪些好處呢?

  感覺不就是一個負數而已,非要搞的這么彎彎繞,我反正是暈了,那接下來就看下二進制補碼的好處

  那我們之前說的判斷最高位是1還是0來區分正負,那接下來我們就用兩種表示法來計算作比較:

  舉例:-10

  表達式:20 + (-10)

  1>.最高位區分正負:-10的二進制數為10001010

    二進制計算:00010100 + 10001010 = 10011110

    10011110轉換成十進制是30,根據最高位區分正負,結果就是-30

  2>.再來看看二進制補碼的方式進行計算:-10的二進制補碼(11110101 + 1 = 11110110(246))

    二進制計算:00010100 + 11110110 = 100001010 

    而咱們剛才已經說了,假設計算機是8位的,那么這個結果超過8位,第九位會被舍棄,也就是00001010,結果就是10

五、為什么正數加法適用於二進制補碼呢?

  接下來我們求證一下X-Y(x + (-Y))這個表達式,相信大家就明白了(8位機)

  Y的二進制補碼由上面的講解大家都知道是:(11111111 - Y) + 1 ,所以也就是X加上Y的二進制補碼,表達式可以寫成如下格式:X + (11111111 - Y) + 1

  得到這個表達式就好辦了,接下來我們分成兩種情況來解釋:

  1>.那就是X小於Y,那么結果肯定是個負數了,我們采用二進制的補碼的逆運算,求出它對應的正絕對值,再在前面加一個負號就可以了

    第一步:計算Z、X、Y的二進制補碼的表達式 Z = -((11111111 - Z) + 1);X = (11111111 - X) + 1;Y = (11111111 - Y) + 1;

    第二步:根據表達式X + (11111111 - Y) + 1來替換計算:-( ( ( 11111111 - X) + 1 ) - ( ( 11111111 - Y ) + 1 ) ) = -(11111111 - X + 1 - 11111111 + Y - 1) = -( -X + Y) = X - Y; 

  2>.X大於Y,那結果肯定是正數,那意味着Z肯定大於11111111,那根據8位機,第九位溢出了,就要舍去,表達式為(不太明白...):

    Z = Z - 100000000 = X + (11111111 - Y) + 1 - 100000000 = X - Y;

  文章出自:http://www.ruanyifeng.com/blog/2009/08/twos_complement.htm

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM