2018-2019-1 20189206 《深入理解計算機系統》第二章學習筆記
2018-2019-1 20189206 《深入理解計算機系統》第五週學習總結
教材學習內容總結
本章主要研究三種重要的數字表示,分別是無符號編碼、補碼編碼和浮點數編碼。其中,無符號編碼表示大於或等於零的數字,補碼編碼用來表示有符號整數,浮點數編碼是科學計數法的以2為基數的版本。
第二章 資訊的表示和處理
資訊儲存的方式
- 最小可定址的記憶體單位————8位的塊,也稱為位元組
- 機器級程式將記憶體視為一個非常大的陣列,稱為虛擬記憶體
- 記憶體的每個位元組都由唯一的數字來表示,稱為地址
十六進位制表示方式
- 一個位元組的
對應的二進位制表示為 \(00000000_2 至 11111111_2\)
對應的十進位制表示為 \(0_{10} 至 255_{10}\)
對應的十六進位制表示為 \(00_{16} 至 FF_{16}\)(以0x或者0X開頭的數字為十六進位制表示) 特殊的轉換方法
當值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
字資料大小
- 每個計算機都有一個字長,用來指明指標資料的標稱大小。 字長決定的最重要的系統引數就是虛擬地址空間的最大大小。對於一個字長為w的機器,虛擬地址的範圍為\[ 0 至 2^w -1 \]
- 多位元組物件被儲存為連續的位元組序列,物件的地址為使用位元組中最小地址
- 大端法:最高有效位元組儲存在前面(即先儲存最高有效位元組)
- 小端法:最低有效位元組儲存在前面(先儲存最低有效位元組)
- 假設0x01234567
- 大端法儲存為 01 23 45 67 (地址從左至右增大)
- 小端法儲存為 67 45 23 01 (地址從左至右增大)
- 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語言會將有符號數強制型別轉換為無符號數,並假設這兩個數都是非負的。
擴充套件一個數字位的表示
- 將無符號數轉換為一個更大的資料型別——零擴充套件
- 將補碼轉換為一個更大的資料型別——符號擴充套件(新增最高有效位的值)
截斷數字
- 截斷無符號數
令\[\vec{x} = [x_{w-1},x_{w-2},\cdots,x_0]\] 現截斷該位向量k位的結果是\[x' = x mod 2^k\]
- 截斷補碼數值
令\[\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\)
- 除以2的冪的無符號除法
浮點數
二進位制小數
表示方法:$ 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時,得到的值表示無窮
- 浮點標準用\[ V= (-1)^s * M * 2^E \] 來表示一個數
【注】浮點運算只由有限的範圍和精度,並且不遵守結合律。
總結
本章重點在於用數學公式準確定義出計算機中使用的幾種資料型別,內容很多,需要好好總結和複習。通過直接運算元字級的位表示,得到了幾種算數運算的方式。針對不同的機器,變數型別儲存的大小也不同、儲存方式不同,為了能使編寫的程式在全部範圍內正確工作,可以實現跨越不同的機器、作業系統和編譯器的組合,對於這種數學原理的學習是十分重要的。
第二章主要從資訊儲存的方式、整數表的方法(無符號編碼、補碼編碼)以及相關操作、整數運算(無符號運算、補碼運算)、浮點數(兩種表示方式)等方面介紹了資料的儲存表示方式,進行計算的結果等內容。