計算機概論-資料儲存

講完了數字系統,這一篇是講關於資料儲存,我挑了數字來講,其他的我覺得書本看過去就好。

在電腦裡面的資料

位元(bit)是電腦儲存資料的最小單位,數值為0或1

每八個位元為一個位元組(byte)

儲存數字

整數

無號整數

無號整數是大於等於零的整數,範圍是零到無限大

但是電腦的儲存空間有限,所以數字會有表達範圍

假如電腦能儲存的空間有n位元,那就表示電腦能表達的最大數字為 $ 2^n-1 $

那麼在電腦中是如何儲存n位元的無號整數的呢

  • 將數字轉為二進位
  • 如果不滿n位元,則在前面補零

例如:將7儲存為8位元的無號整數

  • 轉為二進位為 $ (111)_2 $
  • 在前面補零到八個位元為止 $ (00000111)_2 $

如果將兩個整數相加但相加結果超出n位元的表達範圍(邊界),稱之為overflow

例如在8位元下

$ (11111111)_2+(00000001)_2 $ 應該等於 $ (100000000)_2 $

但是空間只有8位元的情況下

第九個位元會被捨去

就會使結果變成 $ (00000000)_2 $

有號整數(sign-and-magnitude)

那怎麼表達正負號呢

於是就定義了最前面(最左邊)的位元來表示正負號

0表示正號,1表示負號

雖然在n位元下,能表達的數字範圍少了一半,但總算能表達正負號了

例1:28存為8位元有號整數時

  • 先轉為二進位 $ (11100)_2 $
  • 補零補到七位元 $ (0011100)_2 $
  • 視正負號補上第八位元 $ (00011100)_2 $

例2:-28存為8位元有號整數時

  • 先轉為二進位 $ (11100)_2 $
  • 補零補到七位元 $ (0011100)_2 $
  • 視正負號補上第八位元 $ (10011100)_2 $

在這邊overflow仍然是存在的

注意:這種做法會有正零跟負零喔出現喔

二補數

雖然解決了表達正負號的問題,但電路上的實作卻遇到一個問題

加法跟減法需要分開實作,於是就有人想了,能不能兼具實作方便又能表達正負數

於是就有了二補數,做法為:

  • 將數字做一補數
  • 將數字加1

何謂一補數呢?只要將原數字的二進位反轉就是一補數了

例如8位元下, $ (00000101)_2 $ 的一補數是 $ (11111010)_2 $

而 $ (5)_{10} = (00000101)_2 $ 的二補數就是 $ (11111010)_2 $ 再加1,變成 $ (-5)_{10} = (11111011)_2 $

到底為什麼二補數可以讓減法用加法解決呢

例如 $ 1-1=0 $,我們可以將減法當作加上一個負值,變成 $ 1+(-1)=0 $

來檢驗一下這條算式是不是對的

1為 $ (00000001)_2 $,-1為 $ (11111111)_2 $

兩個相加等於 $ (100000000)_2 $,但是第九個位元會被捨去

所以就變成了 $ (00000000)_2 $

又例如 $ 5-4=5+(-4)=(00000101)_2+(11111100)_2=(100000001)_2 $

去掉第九位元之後就變成 $ (00000001)_2=(1)_{10} $

浮點數

正規化與IEEE標準

在儲存浮點數前,要先將二進位數字化為適當的科學記號,也就是正規化,然後按照IEEE訂的標準儲存

正規化就是將數字轉為 $ 1.xxxxx*2^{exp} $ 的形式

例如 $ (0.000000101001)_2 $ 要化為 $ 1.01001*2^7 $

然後我們可以得到三個部分

  • Sign (正負號)
  • Exponent (指數)
  • Mantissa (尾數)

舉 $ 1.01001*2^7 $ 為例,Sign就是+,Exponent為7,Mantissa為01001

取出這三個部分後,就可以按照IEEE標準儲存浮點數了

IEEE規定32位元浮點數的Sign為1位元,Exponent為8位元,Mantissa為23位元

64位元浮點數的Sign為1位元,Exponent為11位元,Mantissa為52位元

其中Exponent不是用二補數儲存,而是採用無號整數

負數均位移 $ 2^{Exponent-1}-1 $,也就是加 $ 2^{Exponent-1}-1 $

例如1位移之後變128,-1位移之後變126

儲存浮點數的步驟:

  • 確認正負號 (0 or 1)
  • 將數字轉成二進位
  • 正規化
  • 找出Exponent與Mantissa
  • 將結果連接起來

例如-0.0234375:

  • 確認正負號:1
  • 將數字轉為二進位:$ (0.0000011)_2 $
  • 正規化:$ (1.1)_2*2^{-6} $
  • 找出Exponent與Mantissa:$ E=-6+127=121=(01111001)_2 $ 且 $ M=(1)_2 $
  • 將結果連接起來:$ \overbrace{1}^{Sign}\overbrace{01111001}^{Exponent}\overbrace{10000000000000000000000}^{Mantissa} $

有一個特別情況是數字為0的時候

不是00111111100000000000000000000000

也不是10111111100000000000000000000000喔XD

IEEE有特別規定所有位元為0的時候表示數字為0

overflow and underflow

overflow之前就談過了

如果你試圖存取超過 $ \pm(1.11111111111111111111111)_2*2^{128} $ 的數字

記憶體就會炸裂給你看www

underflow是指試圖存取比範圍更小的數字

也就是 $ \pm(0.00000000000000000000001)_2*2^{-127} $

截斷誤差

如果你試圖將一個極大一個極小的數字相加就會產生截斷誤差

例如 $ (11111111111111111111.11)_2+(0.00000000000000000000001)_2 $

結果應該是 $ (11111111111111111111.11000000000000000000001)_2 $

正規化後變成 $ (1.111111111111111111111000000000000000000001)_2*2^{19} $

但是在儲存的時候,尾數只有23位元

也就是11111111111111111111100會被儲存,最後的1卻不見了

所以在做浮點數運算的時候要非常小心