計算機信息的表示與存儲

引子

這幾天在看HashMap的源碼,發現其源碼中有一些非常巧妙的位運算,而位運算又牽涉到原碼、反碼、補碼等計算機信息的表示。所以,我就在這裏系統地總結一下這部分的知識,一來加深自己的記憶,而來希望可以幫到大家。

信息的表示

本節中的範例大多來自於《C++程序語言設計》這本書,各位可以去參考一下~

二進制

幾乎所有的計算機都採用的是二進制數系。當數據被轉換爲二進制數後,計算機才能對其進行處理。當然,還有一些常見的進位數制我們也需要了解:

進    制 基數 進位原則 基本符號
二進制 2 逢 2 進 1   0,1
八進制 8 逢 8 進 1   0,1,2,3,4,5,6,7
十進制 10 逢 10 進 1   0,1,2,3,4,5,6,7,8,9
十六進制 16 逢 16 進 1   0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F

採用二進制碼錶示信息,有如下幾個優點:

  • 易於物理實現

具有兩種穩定狀態的物理器件是很多的:如門電路的導通與截止,電壓的高與低。他們都恰好可以對應 0 和 1 兩個符號。假如採用十進制,要製造具有10種穩定狀態的物理電路,那是非常困難的。

  • 二進制數運算簡單

經過數學推導可以證明:對R進制的算數求和、求積規格各有 R(R+1)/2 種。如果採用十進制,就有 55 中求和與求積的運算規則;而二進制僅有3種,因此就簡化了運算器等物理器件的設計。

  • 機器可靠性高

由於電壓的高低、電流的有無 等都是一種質的變化,兩種狀態分明。所以二進制編碼的抗干擾能力強,鑑別信息的可靠性高。

  • 通用性強

二進制編碼不僅可以表示數值,而且還可以用於 非數值信息的編碼。比如,布爾值 True、False 就可以分別和 1、0 對應,從而爲計算機實現邏輯運算與判斷提供了方便。

當然,二進制編碼也有一些不足:它表示數的容量最小;表示同一個數,二進制比其他進制需要更多的位數。

進制轉換

這一部分,我直接給出幾個進制轉化的例子,大家一看應該就能明白。

R進制轉十進制

如下圖,下面是最常見的 2進制 轉 10進制:

如圖,第二個例子是 帶有小數的二進制數 轉換爲 十進制數。大家一看應該就能明白。

上面兩個例子分別是 八進制、十六進制的數轉換爲 十進制數。這部分很簡單,不多加闡述。

十進制轉R進制

關於十進制數轉換爲R進制的數,這裏分爲兩部分說明:整數的轉換 與 小數的轉換。

整數轉換:

十進制的整數轉換爲R進制的整數,採用的是“除R取餘法”。下面看例子:

也就是說,(68)_{10}=(1000100)_{2}。再看一個例子,將(168)_{10} 轉換爲 八進制數,採用除8取餘:

也就是說,(168)_{10} = (250)_{8} 。其他的進制轉化也是類似,十進制轉十六進制時,採用 除16取餘 即可。這裏就不多加介紹了。

小數轉換:

十進制整數轉換爲R進制的整數時,採用的方法是“除R取餘”。當需要轉換的十進制數包含小數位數時,可以分爲兩部分處理:整數部分,處理方法同上,採用“除R取餘”;小數部分,採用“乘R取整”。下面看例子:

(0.3125)_{10} 轉換爲 二進制數:

如上圖,我們將小數部分依次乘以基數,轉換爲R進制就乘以R。依次乘下去,直到小數部分爲0,或者達到所需要的精度爲止(小數部分可能永遠都不爲0。也就是說,十進制小數往往不能精確地轉化爲等值的R進制小數)。最終得到結果:(0.3125)_{10}=(0.0101)_{2} 。

我們已經知道(68)_{10}=(1000100)_{2},也知道(0.3125)_{10}=(0.0101)_{2},那也就是說:(68.3125)_{10}=(1000100.0101)_{2}。將整數部分和小數部分拼接起來即可。

二、八、十六進制間的轉換

二、八以及十六進制 三種進制的數之間存在一些內在聯繫:每一位八進制數相當於3位二進制數({\color{Red} 8=2^3}),每一位十六進制的數相當於4位二進制數({\color{Red}16=2^4 })。

二進制數,從小數點開始,向左右分別按三(四)位爲一個單元劃分,每個單元單獨轉換成爲一個八進制(十六進制)的數,就完成了二進制到八進制(十六進制)的轉換。在轉換時,位組的劃分是以小數點爲中心向兩邊延伸,中間的 0 不能省略,兩頭不夠時可以補 0 。

八進制(十六進制)的每一位,分別獨立轉換成三位(四位)二進制數,除了左邊的最高位,其他位如果不足三位(四位)的要用 0 來補足,按照由高位到低位的順序寫到一起,就是相應的二進制數。

下面看幾個例子:

上圖多看幾遍,也是很容易理解的。

信息的存儲

在計算機內部,各種信息都是以二進制編碼形式進行存儲。

信息存儲的單位

信息存儲的單位通常採用“位”、“字節”和“字”。

  • 位:bit,度量數據的最小單位,表示1位二進制信息。
  • 字節:Byte,一個字節由 8 位二進制數字組成(1 Byte = 8bit)。字節是信息存儲中最常用的基本單位。計算機的存儲器通常也是以多少字節來表示它的容量。
  • 字:Word,字是位的組合,並作爲一個獨立的信息單位處理。字又稱爲“計算機字”,它的含義取決於機器的類型、字長以及使用者的要求。常用的固定字長有 8位、16位、32位等。
  • 機器字長:在討論信息單位時,還有一個與機器硬件指標有關的單位,這就是機器字長。機器字長一般是指參加運算的寄存器所含有的二進制數的位數,它代表了機器的精度,如 32位、64位等。

二進制數的編碼表示

數值在計算機內是採用二進制編碼表示。數有正負之分,一般情況下,在計算機中使用“0”表示正號,“1”表示負數。符號位放在數的最高位。例如,8位二進制數 A = (+1011011)_{2},\ B=(-1011011) 它們在機器中可以表示爲:

其中最左邊一位代表符號位,連同數字本身一起作爲一個數。

人們研究了符號數的多種二進制編碼方法,其實質是對負數表示的不同編碼。下面介紹一下幾種常見的編碼:原碼、反碼 和 補碼。

注意:在下面的示例中,使用 一個字節存放一個整數,所有整數使用8位二進制碼錶示!

原碼

將 符號 數字化爲 0 或 1,數的絕對值與符號一起編碼,這樣的二進制碼稱爲“原碼”。如上面編碼後的A、B,得到的二進制碼都是原碼。

對於一個整數,編碼方式就是上面例子中編碼A、B那樣,用 0、1分別代表 正好、負號。例如:

對於一個帶符號的純小數,它的原碼錶示就是把小數點左邊一位用作符號位。例如:

採用原碼錶示法時,編碼簡單直觀,與原始值(真值)轉換方便。但是也有一些缺點:

  • 零(0)的表示不唯一。

  • 另一個原因是,使用原碼進行四則運算時,符號位需要單獨處理,並且運算規則複雜。

反碼

反碼很少使用,這這裏講它主要是因爲 反碼是求補碼的中間碼。

對於整數而言,正數的反碼與原碼錶示相同;負數反碼的符號位與原碼相同,仍用“1”表示,其餘各位取反,0變成1,1變成0。

很顯然,和原碼一樣,反碼中,0的表示也不唯一。

對於純小數而言,反碼也類似,小數點左邊的符號位不變,小數點右邊的小數位取反。

補碼

對於一個正數來說,其原碼、反碼、補碼 表示相同。對於一個負數,其補碼由該數反碼最末位加 1 求得。

對於一個純小數,反碼的求法一樣:

從上面的例子中可以看出,零(0)的補碼錶示是唯一的。採用補碼錶示的另一個好處就是,當數值信息參與算數運算時,採用補碼的方式是最簡便的:一是因爲符號位可以作爲數值參加運算,最後仍然可以得到正確的符號,無需單獨處理;二是採用補碼進行運算時,減法運算可以轉化爲加法運算,簡化了硬件中的運算電路。正是由於這些優點,在計算機系統中,數值都採用補碼來表示和存儲。

需要注意的是,補碼的運算結果仍然是補碼。下面看兩個例子:

例一:求 67 - 10 = ?

如上圖,67 與 -10 的補碼如圖,則有:

計算結果記爲R,也就是說,R的補碼爲 00111001。顯然R是個正數,也就是說,R的原碼也爲 00111001。則R = 57。

例二:求10 - 67 = ?

如上圖,我們計算出 +10 與 -67 的補碼,然後計算:

結果記爲R,則R的補碼爲 11000111,從符號位看,R是個負數。要計算結果值,則我們要將結果的補碼轉換爲原碼:只需要對補碼再求補碼,即可還原爲原碼。

計算得出,R的原碼爲 10111001,則 R = -57。

總結

技術更新換代太快,但是計算機總是圍繞着一些基本理論在發展。所以,我們在瘋狂學習新技術時,也應該好好掌握好這些基礎知識。技術變化很快,然而萬變不離其宗。

參考文檔

1、《C++語言程序設計》第四版,鄭莉·著。第一章:緒論

2、《Java編程思想》第四版,Bruce Eckel·著。第三章:操作符

3、https://zhidao.baidu.com/question/535670583.html

發佈了47 篇原創文章 · 獲贊 43 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章