1. 程式人生 > >2018-2019-1 20189206 《深入理解計算機系統》第二章學習筆記

2018-2019-1 20189206 《深入理解計算機系統》第二章學習筆記

2018-2019-1 20189206 《深入理解計算機系統》第五週學習總結

教材學習內容總結

本章主要研究三種重要的數字表示,分別是無符號編碼、補碼編碼和浮點數編碼。其中,無符號編碼表示大於或等於零的數字,補碼編碼用來表示有符號整數,浮點數編碼是科學計數法的以2為基數的版本。

第二章 資訊的表示和處理

資訊儲存的方式

  1. 最小可定址的記憶體單位————8位的塊,也稱為位元組
  2. 機器級程式將記憶體視為一個非常大的陣列,稱為虛擬記憶體
  3. 記憶體的每個位元組都由唯一的數字來表示,稱為地址

十六進位制表示方式

  1. 一個位元組的
    對應的二進位制表示為 \(00000000_2 至 11111111_2\)

    對應的十進位制表示為 \(0_{10} 至 255_{10}\)
    對應的十六進位制表示為 \(00_{16} 至 FF_{16}\)(以0x或者0X開頭的數字為十六進位制表示)
  2. 特殊的轉換方法

    當值x是2的非負整數的n次冪時即 \[x=2^n\] 可以將x寫成1後面加n個0的形式。
    當n表示為 n=i+4j 時(0<=i<=3),x對應的十六進位制數字可以寫成1、2、4、8後面跟J個0
    例如: \[ 512 = 2^9 \] 知 n=1+2*4 故2048對應的16進位制是 0x200

字資料大小

  1. 每個計算機都有一個字長,用來指明指標資料的標稱大小。 字長決定的最重要的系統引數就是虛擬地址空間的最大大小。對於一個字長為w的機器,虛擬地址的範圍為\[ 0 至 2^w -1 \]
    程式最多訪問2^w個位元組。
  2. 多位元組物件被儲存為連續的位元組序列,物件的地址為使用位元組中最小地址
    • 大端法:最高有效位元組儲存在前面(即先儲存最高有效位元組)
    • 小端法:最低有效位元組儲存在前面(先儲存最低有效位元組)
    • 假設0x01234567
      • 大端法儲存為 01 23 45 67 (地址從左至右增大)
      • 小端法儲存為 67 45 23 01 (地址從左至右增大)
  3. linux32 Windows和linux64 均為小端機器,可以記為閱讀順序和儲存順序相反。

下面show_bytes函式的作用是打印出每個以十六進位制表示的位元組,其中輸入是一個位元組序列的地址。

void show_bytes(byte_pointer start,size_t len)
{
    size_t i;
    for(i=0;i<len;i++)
    {
        printf("%.2x",start[i]);
    }
    printf("\n");
}

void show_int(int x)
{
    show_bytes((byte_pointer)&x,sizeof(int));
}

實現的功能就是輸出int型每個位元組對應的十六進位制表示。

布林代數

    布林運算     邏輯運算    命題邏輯
       ~          NOT        ┐
       &          AND        ∧
       |          OR         ∨
       ∧         異或        ⊕
  • 位級運算的常用用法是實現掩碼運算,掩碼錶示從一個數中選出的位的集和。
    x & 0xFF 得到的結果就是x最低有效位元組組成的值,其餘位元組被置0,之後表示式~0 得到的結果就是全為1 的掩碼。

【注】注意區分C語言中的邏輯運算與位級運算

C語言的邏輯運算是|| &&和!,分別對應命題邏輯中的OR、AND和NOT運算。邏輯運算認為所有的非零值都為真,引數零表示假,運算結果只由0和1。

邏輯運算中如果第一個引數求值就能確定表示式的值,邏輯運算不會對第二個引數求值

位移運算

  • 位移運算分為左移和右移
    • 左移 X向左移,丟棄最高的k位,並在右端補0
    • 右移 X向右移,丟棄最低的k位
      • 算數右移 在左端補k個最高有效位的值
      • 邏輯右移 在左端補0

幾乎所有的編譯器/機器組合都會對有符號數使用算數右移,而對於無符號數,右移必須是邏輯右移。

整數表示

無符號數只能表示非負數,而補碼編碼能夠表示負數、0和正數。

  • 無符號數的編碼

    • 無符號數的定義
      對於向量 \[ \vec{x} = [x_{w-1},x_{w-2},\cdots,x_0] \]

      \[B2U_w (\vec{x}) = \sum_{i=0}^{w-1}x_i2^i\]

    • 無符號數所能表示的值的範圍
      [0 0 …… 0] 到 [1 1 …… 1]即
      \[UMax_w = \sum_{i=0}^{w-1}2^i = 2^w-1\]

    • 無符號編碼的唯一性
      函式B2U是一個雙射,將每一個長度為w的位向量,對映為0~2^w-1之間的唯一一個值,這種對映是一一對應的關係,即可以反向操作。

  • 補碼編碼
    最常見的有符號數的計算機表示方式就是補碼形式,這種形式下,將字的最高有效位解釋為負權。

    • 補碼編碼的定義

    對於向量 \[ \vec{x} = [x_{w-1},x_{w-2},\cdots,x_0] \]

    \[B2T_w (\vec{x}) = -x_{w-1}2^{w-1} + \sum_{i=0}^{w-1}x_i2^i\]

    最高有效位稱為符號位,符號位為1時,表示值為負數;符號值為0時,值為非負。

    • 補碼所能表示的範圍

    它能表示的最小值是[1 0 …… 0] 其整數值為 \[TMin_w = -2^{w-1} \]
    最大值為[0 1 …… 1] 其整數值為\[TMax_w = \sum_{i=0}^{w-1}2^i = 2^w-1\]

    • 補碼有著與無符號數相同的雙射函式
    • 最大無符號數剛好比補碼的最大值的兩倍大一\[UMax_w=2TMax_w + 1 \]

有符號數和無符號數之間的轉換

  • 強制型別轉換的結果保持位不變,只是改變了解釋這些位的方式。處理同樣字長的有符號數和無符號數之間的轉換一般規則是:數值可能會改變,但是位模式不變

  • 補碼轉換為無符號數

對滿足\[TMin_w\leq x \leq TMax_w \]的x有:
\[T2U_w(x) =\begin{cases} x+2^w & x <0 \\\ x & x \geq 0 \end{cases}\]

從以上表達式可以看出,將一個有符號數轉為它相應的無符號數時,負數就被轉換成了大的整數,非負數則會保持不變。

  • 無符號數轉換為補碼

對滿足\[0 \leq u \leq UMax_w \]的x有:
\[U2T_w(u) =\begin{cases} u & x \leq TMax_w \\\ u-2^w & u>TMax_w \end{cases}\]

從以上表達式可以看出,講一個無符號數轉換為補碼時,U2T把大於2^w-1的數轉化成了負數。

從上述兩個公式可以看出,對於在範圍\[ 0 \leq x \leq TMax_w \]的範圍內的數字有著相同的補碼和無符號數表示。對於這個範圍以外的數需要加上或者減去2^w

  • C語言中,當執行一個運算時,它的一個運算數是有符號的,另一個運算數是無符號的,那麼C語言會將有符號數強制型別轉換為無符號數,並假設這兩個數都是非負的。

擴充套件一個數字位的表示

  1. 將無符號數轉換為一個更大的資料型別——零擴充套件
  2. 將補碼轉換為一個更大的資料型別——符號擴充套件(新增最高有效位的值)

截斷數字

  1. 截斷無符號數

\[\vec{x} = [x_{w-1},x_{w-2},\cdots,x_0]\] 現截斷該位向量k位的結果是\[x' = x mod 2^k\]

  1. 截斷補碼數值
    \[\vec{x} = [x_{w-1},x_{w-2},\cdots,x_0]\] 現截斷該位向量k位的結果是\[x' = U2T_k(x mod 2^k)\]即把最高位的權重從正變為負。

整數運算

  • 無符號加法
    定義無符號數加法,該操作是把整數和x+y截斷為w位得到的結果,再把這個結果看作是一個無符號數。可以被看作是一種形式的模運算
    對於x、y滿足\[ 0 \leq x,y<2^w \]有:
    \[x + y =\begin{cases} x+y & x+y \leq 2^w \\\ x+y-2^w & 2^w \leq x+y <2^{w+1} \end{cases}\]

當x+y的結果s小於x或者小於y的時候,可以判定無符號數的加法出現了溢位。

  • 無符號數求反

模數加法形成了一個阿貝爾群,對於每個x值必定有有一個加法逆元。
對於滿足\[ 0 \leq x <2^w \]的任意x值,其無符號加法逆元為
\[- x =\begin{cases} x & x=0 \\\ 2^w-x & x>0 \end{cases}\]

  • 補碼加法
    對於滿足\[-2^{w-1} \leq x,y \leq 2^{w-1}-1 \]的整數x和y 有
    \[x + y =\begin{cases} x+y-2^w & 2^{w-1} \leq x+y & 正溢位 \\\ x+y & -2^{w-1} \leq x+y <2^{w-1} &正常\\\ x+y+2^w & x+y<-2^{w-1} & 負溢位 \end{cases}\]

  • 補碼的非
    對於滿足\[ TMin\_w \leq x <TMin\_w \]的任意x值,其補碼的非為
    \[- x =\begin{cases} TMin\_w & x=TMin\_w \\\ -x & x>TMin\_w \end{cases}\]

  • 無符號和補碼乘法
    將一個數截斷w就等價於計算該值的模2^w
    對於無符號和補碼乘法來說,乘法運算的位級表示都是一樣的。

  • 乘以常數

由於在大多數機器上,整數乘法的指令需要10個或者更多的時鐘週期,其他整數運算只需要1個時鐘週期。編譯器使用了優化,試著用位移和加法的運算組合代替乘以常數因子的乘法。
原理: 設x的位模式為 \([x_{w-1},x_{w-2},\cdots,x_0]\)表示無符號整數,那麼對於任何$k \leq 0 $都認為 \([x_{w-1},x_{w-2},\cdots,x_0,0,0,\cdots,0]\) 給出了 \(x*2^k\) 的w+k位的無符號表示,右邊增加了k個0。
可以看出,左移一個數值相當於執行一個與2的冪相乘的無符號乘法

例如:一個程式包含表示式 x*14 利用 $14 =2^3+2^2+2^1 $ 可以將該乘法重寫(x<<3)+(x<<2)+(x<<1),將一個乘法替換為位移和兩個加法。
或者利用 $14 =2^4-2^1 $ 重寫成 (x<<4)-(x<<1)

  • 除以2的冪
    • 除以2的冪的無符號除法
      假設有無符號數值x和k,且 $0 \leq k <w $ 則表示式 x>>k 產生結果\(\lfloor x/2^k \rfloor\)
    • 除以2的冪的補碼除法
      假設有補碼數值x和無符號數值k,且 $0 \leq k <w $ 則表示式執行算術位移 x>>k 產生結果\(\lfloor x/2^k \rfloor\)

浮點數

  • 二進位制小數
    表示方法:$ b_m b_{m-1} \cdots b_1 b_0.b_{-1} b_{-2} \cdots b_{-n} $
    這個表達描述的定義如下:
    \[b = \sum_{i=-n}^{m}2^i*d_i \]

  • IEEE浮點表示
    • 浮點標準用\[ V= (-1)^s * M * 2^E \] 來表示一個數
      • 符號:s決定了這個數是負數(s=1)還是正數(s=0)
      • 尾數:M是一個二進位制小數,範圍是1~2-ε 或者 0~1-ε
      • 階碼:E的作用是對浮點數加權,這個權重是2的E次冪
    • 將浮點數的位表示劃分為3個欄位,分別對這些值編碼
      • 一個單獨的符號位s
      • k位的階碼欄位\(exp=e_{k-1} \cdots e_1 e_0\)編碼階碼E
      • n位的小數字段$frac=f_{n-1} \cdots f_1 f_0 $編碼尾數M
    • 規格化的值
      • exp的位模式不會全為0或全為1 階碼欄位被表示為以偏置形式表示的有符號整數。E= e-bias e為無符號數 \(bias=2^{k-1}-bais\)
      • 小數字段frac,尾數定義為M=1+f
    • 非規格化的值
      • 階碼E全為0時是非規格化的形式,此時 E=1-Bias 尾數值M=f
    • 特殊值
      • 階碼全為1時,得到的值表示無窮

【注】浮點運算只由有限的範圍和精度,並且不遵守結合律。

總結

本章重點在於用數學公式準確定義出計算機中使用的幾種資料型別,內容很多,需要好好總結和複習。通過直接運算元字級的位表示,得到了幾種算數運算的方式。針對不同的機器,變數型別儲存的大小也不同、儲存方式不同,為了能使編寫的程式在全部範圍內正確工作,可以實現跨越不同的機器、作業系統和編譯器的組合,對於這種數學原理的學習是十分重要的。
第二章主要從資訊儲存的方式、整數表的方法(無符號編碼、補碼編碼)以及相關操作、整數運算(無符號運算、補碼運算)、浮點數(兩種表示方式)等方面介紹了資料的儲存表示方式,進行計算的結果等內容。