1. 程式人生 > >二進制數的編碼表示

二進制數的編碼表示

兩個 說明 計算 範圍 是否 數據 效果 需要 符號位

數值信息在計算機內是采用二進制編碼表示。數有正負之分,一般情況下,用"0"表示正號,"1"表示負號,符號位放在數的最高位。
例如,8位二進制數A = (+1011011),B = (-1011011),它們在機器中可以表示為:
A:01011011
B:11011011

計算機中幾種常用的編碼----原碼、反碼和補碼。

1.原碼
將符號位數字化為0或1,數的絕對值與符號一起編碼,即所謂"符號-絕對值表示"的編碼,稱為原碼。
例如:
整數:
X = +1011011,原碼:[X]原 = 01011011;
X = -1011011,原碼:[X]原= 11011011;
小數:

對於一個帶符號的純小數,它的原碼表示就是把小數點左邊一位用作符號位。
X = 0.1011,原碼:[X]原 = 0.1011;
X = -0.1011,原碼:[X]原 = 1.1011;

            當采用原碼表示法時,編碼簡單直觀,與真值轉換方便。但原碼也存在一些問題,一是零的表示不唯一,因為:[+0] = 000···0,[-0] = 100···0  零有二義性,
            給機器判零帶來麻煩。二是用原碼進行四則運算時,符號位需要單獨處理,且運算規則復雜。例如加法運算,若兩數同號,兩數相加,結果取共同的符號;
            若兩數異號,則要大數減去小數,結果冠以大號的符號。此外,借位操作如果用計算機硬件來實現是很困難的。

2.反碼
反碼很少使用,但作為一種編碼方式和求補碼的中間碼,我們還是要學習一下的。
正數的反碼與原碼表示相同。
負數反碼的符號位與原碼相同(仍用1表示),其余各位取反(0變1,1變0)。例如:
X = +1100110, [X]原 = 01100110,[X]反 = +1100110;
X = -1100110,[X]原 = 11100110,[X]反 = 10011001;
X = +0000000,[X]原 = 00000000,[X]反 = 00000000;
X = -0000000,[X]原 = 10000000,[X]反 = 111111111;
和原碼一樣,反碼中的零的表示也不唯一。
當X為純小數時,反碼的表示如下:
X = 0.1011,[X]原 = 0.1011,[X]反 = 0.1011;
X = -0.1011,[X]原 = 1.1011,[X]反 = 1.0100;

3.補碼
(1)模數的概念
模數從物理意義上講,是某種計量器的容量。例如,我們日常生活中用到的鐘表,模數就是12。鐘表計時的方式就是達到12就從零開始(扔掉一個12),這在數學上是一種"取模(或取余)運算(mod)"。例如:14%12 = 2。
如果現在的準確時間是6點整,而你的手表指向8點,怎樣把表撥準呢?可以有兩種方法:把表往後撥2小時,或把表往前撥10小時,效果是一樣的。即:
8-2 = 6
(8+10)%12 = 6

         在模數系統中,8-2 = 8+10 (mod 12)
         上式之所以成立,是因為2與10對模數12是互為補數的(2+10 = 12)。因此,可以認可這樣一個結論:在模數系統中,一個數減去另一個數,或者一個數加上一個負數,等於第一個數加上第二個數的補數:
                                                                                                                                                 8+(-2) = 8+10 (mod 12)
            我們稱10為-2在模12下的"補碼"。負數采用補碼表示後,可以使加減法統一為加法運算。
            在計算機中,機器表示數據的字長是固定的。對於n位數來說,模數的大小是:n位數全為1,且末位再加1。實際上模數的值已經超過了機器所能表示的數的範圍,因此模數在機器中是表示不出來的。若運算結果大於模數,則模數自動丟掉,也就等於實現了取模運算。
            如果有n位整數(包括一位符號位),則它的模數為2^n;如果有n位小數,小數點前一位為符號位,則它的模數為2。

    ***(2)補碼表示法***
    由以上討論得知,對於一個二進制負數,可用其模數與真值做加法(模減去該數的絕對值)求得其補碼。
    例:  X = -0110    [X]補 = 2^4 + (-0110) = 1010
             X = -0.1011  [X]補 = 2 + (-0.1011) = 1.0101
                     由於機器中不存在數的真值形式,用上述公式求補碼在機器中不易實現,但從上式可推導出一個簡便方法。
                     "對於一個負數,其補碼由該數反碼的最末位加1求得。"
                    "對於正數來說,其原碼、反碼、補碼形式相同。”

                    補碼的特點之一就是零的表示唯一。
                      [+0]補 = 0 0 ···0           [-0]補 = 1 1 ··· 1 + 1 = 1 0 0 ··· 0
                                      |_____|                        |______|          |  |______|
                                                       n位                               n位              |      n位
                                                                                               |_ _ _ _ _ _ _ 自動丟失 
                    這種簡便的求補碼方法經常被簡稱為"求反加1"。

(3)補碼的運算規則
采用補碼表示的另一個好處就是當數值信息參與算術運算時,采用補碼方式是最方便的。首先,"符號位可作為數值參加運算,"最後仍可得到正確的結果符號,符號無需單獨處理;其次,采用補碼進行運算時,減法運算可轉換為加法運算,簡化了硬件中的運算電路。
例如:
計算67-10=?
[+67]原 = 01000011, [+67]補 = [+67]原
[-10]原 = 10001010, [-10]補 = 11110110

                  0 1 0 0 0 0 1 1        [+67]補
            +  1 1 1 1 0 1 1 0        [-10]補
            ——————————————
             1 0 0 1 1 1 0 0 1   = 57
              |____________________________ 最高位的進位自然丟失
                 由於字長只有8位,因此加法最高位的進位自然丟失,達到了取模效果(即丟掉了一個模數)。
                 應當指出,"補碼運算的結果仍為補碼。" 上例中,從結果符號位得知,結果為正,所以補碼即原碼,轉換成十進制數為57。
       如果結果為負,則是負數的補碼形式,若要變成原碼,需要對補碼再求補,即可還原為原碼。
 例如:
         10 - 67 = ?
                 [+10]原 = 00001010 = [+10]補
                 [-67]原 = 11000011     [-67]補 = 10111101

                        0 0 0 0 1 0 1 0
                +  1 0 1 1 1 1 0 1
                ——————————
                      1 1 0 0 0 1 1 1

                            [結果]補 = 11000111,[結果]原 = 10111001
                            所以結果的真值為-0111001,十進制為-57。

                    以上兩個例子是否就可以說明補碼運算的結果總是正確的呢?請看下面的例子:
例如:
        85 + 44 = ?
                      0 1 0 1 0 1 0 1
                    +  0 0 1 0 1 1 0 0
                ———————————
                          1 0 0 0 0 0 0 1
                    從結果的符號位可以看出,結果是一負數。但兩個整數相加不可能是負數,問題出在什麽地方呢?原來這是由於"溢出"造成的,即結果超出了一定位數的二進制數所能表示的數的範圍。

            以上內容節選自清華大學出版社《C++語言程序設計(第4版)》

二進制數的編碼表示