【讀書筆記】CSAPP ch2
目錄
- 第二章 信息的存儲和表示
- 信息存儲
- 十六進制表示法
- 字數據大小
- 尋址和字節順序
- 字符串的表示
- 代碼表示
- 布爾代數
- C語言中的位運算
- C語言中的邏輯運算
- C語言中的移位運算
- 整數的表示
- 整型數據類型
- 數據編碼
- 有符號數和無符號數之間的轉換
- C語言中的有符號數和無符號數的轉換
- 擴展數字的位表示
- 截斷數字的位表示
- 整數的運算
- 無符號數加法
- 補碼加法
- 補碼的非
- 無符號乘法
- 補碼乘法
- 乘常數
- 除以2的冪
- 信息存儲
第二章 信息的存儲和表示
信息存儲
十六進制表示法
(略)
字數據大小
- 大多數計算機使用8bit的塊(字節)作為最小的可尋址的內存單元
- 字長指明了指針數據的標稱大小(?)
- 64位系統和32位系統向後兼容
- C語言中有些數據類型的具體大小依賴於程序的編譯,C99引入
int32_t
int64_t
類型,指明數據的長度 - C標準對不同數據類型的數字的範圍設置了下界,沒有設置上界
尋址和字節順序
- 存儲規則:對象的地址是什麽?在內存中如何排列這些字節?
- 地址:多字節對象的存儲地址為連續字節序列的最小字節地址
- 排列方式:
- 小端法:低字節存在低地址
- 大端法:低字節存在高地址
- 默認規則:書寫時,地址從左往右表示從低到高,字節從左往右表示從高到低
- 關心字節順序的場合:
- 網絡數據傳輸
- 閱讀字節序列
- 規避正常的類型系統,比如強制類型轉換或者聯合允許一種數據類型引用一個對象
- 代碼示例:按字節讀取內容
//按照字節打印數據中的內容 #include<bits/stdc++.h> using namespace std; typedef unsigned char *byte_pointer; void show_bytes(byte_pointer start, int len){ int 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 main(){ int num; cin >> num; show_int(num); return 0; }
字符串的表示
- 用ASCII碼表示
- ASCII碼只能表示英文字符,更一般的字符采用Unicode
代碼表示
- 二進制代碼不兼容,即不同系統上編譯得到的二進制代碼不同
布爾代數
- 運算:與、或、非
- 位向量
- 位向量表示有限集合
C語言中的位運算
- 將十六進制轉換為二進制執行二進制運算,然後將結果轉換為十六進制
C語言中的邏輯運算
- 0表示false,非0表示true
- 與位運算的不同:
- 位運算的參數是0或1
- 邏輯運算有短路原則
C語言中的移位運算
\([x_{\omega - 1}, x_{\omega - 2}, ..., x_0]\)
- 左移:高位舍棄,低位補0 $ [x_{\omega - 1 - k}, x_{\omega - 2 - k}, ... x_0, \underbrace{0, \cdots, 0}_{k個}]$
- 右移:
- 算數右移:補符號位 \([\underbrace{x_{\omega - 1}, ..., x_{\omega -1}}_{k個}, x_{\omega -1}, x_{\omega - 2}, ..., x_k]\)
- 邏輯右移:補0 \([\underbrace{0, ..., 0}_{k個}, x_{\omega - 1}, ..., x_k]\)
整數的表示
整型數據類型
- 典型實現中,負數比正數多1個
- C語言標準中規定(1)固定了數據大小(2)正數和負數對稱
數據編碼
假設整型數據類型有\(\omega\)位,將其表示記作位向量\(\vec x = [x_{\omega - 1}, x_{\omega - 2}, \cdots, x_0]\)
無符號數編碼
- 定義:
\[ B2U_{\omega}(\vec x)=\sum_{i=0}^{\omega - 1} x_i 2 ^ i \]
範圍:\(Umax = \sum\limits_{i = 0}^{\omega - 1} 2 ^ i = 2 ^\omega -1\)
示例:
- 定理:\(B2U_\omega(\vec x)\)是一個雙射
補碼表示
定義:
\[ B2T_{\omega}(\vec x) = -x_{\omega - 1}2^{\omega - 1} + \sum_{i = 0}^{\omega - 2}x_i 2 ^i【註】補碼表示中,最高位被理解為負權 \]
【註】補碼表示中,最高位被理解為負權範圍:\(Tmin = -2^{\omega - 1}, Tmax = \sum\limits_{i = 0} ^ {\omega - 2}2 ^ i = 2 ^{\omega - 1} - 1\)
示例:
定理:\(B2T_\omega(\vec x)\)是一個雙射
【註】
- 補碼的範圍中:\(\vert Tmin\vert = \vert Tmax\vert + 1\)
補碼和無符號數:\(Umax = 2Tmax + 1\)
所有機器都將有符號數表示為補碼,盡管C語言標準沒有明確規定
反碼表示
- 定義:
\[ B2O_{\omega}(\vec x) = -x_{\omega - 1}(2^{\omega - 1} - 1) + \sum_{i = 0}^{\omega - 2}x_i2^i \]
原碼表示
- 定義:
\[ B2S_\omega(\vec x) = (-1)^{x_{\omega - 1}}\times \sum_{i = 0}^{\omega - 2}x_i2^i \]
有符號數和無符號數之間的轉換
- C語言強制類型轉換:不改變位級表示,只改變位的解釋方式
補碼轉無符號數
補碼轉為無符號數:
\[ T2U_\omega(x) = \begin{cases} x + 2 ^\omega & x < 0,\x & x \geq 0 \end{cases} \]推導:
\[ \begin{align} B2U_\omega (\vec x) - B2T_\omega(\vec x) &= x_{\omega - 1}2^\omega \Longrightarrow B2U_\omega(\vec x) = x_{\omega - 1}2^\omega + B2T_\omega(\vec x)\T2U_\omega(x) &= B2U_\omega(T2B_\omega(x)) \&= x_{\omega -1}2^\omega + B2T_{\omega}(T2B_\omega)(x)\&= x_{\omega- 1}2^\omega + x \end{align} \]
- 理解:將補碼中最高位解釋為負權變為解釋為正權,將補碼看做無符號數時,正數不變,負數變為一個更大的數
- 示例:
無符號數轉補碼
- 轉換:
\[ U2T_{\omega}(x) = \begin{cases} u & u \leq Tmax_\omega \u - 2 ^ \omega & u > Tmax_\omega \end{cases} \]
- 推導(同補碼轉無符號數)
總結
C語言中的有符號數和無符號數的轉換
- C語言中默認數字都是有符號
- 聲明一個無符號常量需要在數字後面綴上‘U’
- 一個運算中同時出現有符號數和無符號數時,會被隱式轉換為無符號數
擴展數字的位表示
無符號數的0擴展
- \(u_\omega = [u_{\omega -1}, \cdots, u_0]\longrightarrow u'_{\omega + k} = [\underbrace{0, \cdots, 0}_{k個}, u_{\omega -1}, \cdots, u_0]\)
補碼的符號擴展
- 定義
\[ x_\omega = [x_{\omega - 1}, \cdots, x_0]\longrightarrow x'_{\omega + k} = [\underbrace{x_{\omega-1}, \cdots, x_{\omega - 1}}_{k個}, x_{\omega - 1}, \cdots, x_0] \]
- 推導
\[ \begin{align} B2T_{\omega + 1}(\vec x') &= -x_{\omega -1}2^\omega + \sum_{i = 0}^{\omega - 1}x_i2^i\&= -x_{\omega - 1}2^\omega + x_{\omega -1}2^{\omega - 1} + \sum_{i=0}^{\omega - 2}x_i 2^i\&= -x_{\omega - 1}2^{\omega -1}+\sum_{i=0}^{\omega - 2}x_i 2^i\&= B2T_\omega(\vec x) \end{align} \]
截斷數字的位表示
無符號數的截斷
- 定理
\[ \vec x = [x_{\omega -1 }, \cdots, x_0], \vec x' = [x_{k-1}, \cdots, x_0]\x' = x \mod 2^k \]
- 推導:截斷的部分對應的位權為\(2^{k}, \cdots, 2^\omega\)
補碼的截斷
- 定理
\[ \vec x = [x_{\omega -1 }, \cdots, x_0], \vec x' = [x_{k-1}, \cdots, x_0]\x' = U2T_k(x\mod 2^k) \]
- 推導:以無符號數為中介
整數的運算
無符號數加法
- 定義運算\(+_\omega^u\),將無符號數\(x, y\)相加後截斷\(\omega\)位,可以視作是一種模運算
- 無符號數加法:
對於滿足\(0\leq x, y < 2^\omega\),有:
\[
x+_\omega^u y = \begin{cases}
x + y & x + y < 2 ^ \omega \x + y - 2 ^ \omega & x + y \geq 2 ^\omega
\end{cases}
\]
- 溢出判斷:對於\(s = x+_\omega^uy\),當且僅當\(s < x\quad or\quad s < y\)時發生溢出
- 無符號數求反:模數加法形成了一個阿貝爾群,定義\(x\)的反為:
\[ -_\omega^u x = \begin{cases} x & x = 0\2^\omega - x & x > 0 \end{cases} \]
補碼加法
- 定義運算\(+_\omega^t\),將有符號數\(x, y\)相加後截斷\(\omega\)位,可以視作是一種模運算
- 補碼加法:
\[ x+_\omega^t y=\begin{cases} x+y-2^\omega & 2 ^{\omega - 1} \leq x + y\x+y & -2^{\omega -1 } \leq x + y < 2 ^{\omega -1}\x+y+2^\omega &x + y < -2^{\omega -1} \end{cases} \]
【註】還是來源於截斷,當沒有溢出時,不發生截斷;溢出的情況只會是“正+正”或者“負+負”;“正+正”溢出時,符號位為0,數字部分的最高位變為1(進位導致增加的數字),截斷後原有的符號位會被丟棄,符號位變為1,真實的值為\(x+y=2^{\omega -1} + \sum\limits_{i=0}^{\omega -2}x_i2^i\),截斷後的值為\(x+_\omega^t y- = 2^{\omega -1} + \sum\limits_{i=0}^{\omega -2}x_i2^i\),因此\(x+_\omega^t y = x + y - 2^\omega\);負溢出解釋相似。
- 推導:
有符號和無符號具有相同的位級表示,因此先將參數轉換為無符號數,然後按照無符號數運算,最後將結果轉換為補碼
\[
\begin{align}
x+_\omega^u y &= U2T_\omega(T2U_\omega(x) + T2U_\omega(y))\&= U2T_\omega((x_{\omega-1}2^\omega + y_{\omega - 1}2^\omega+x+y)\mod 2^\omega)\&= U2T_\omega((x+y)\mod 2^\omega)
\end{align}
\]
記\(z=x+y, z' = z\mod 2^\omega, z'' = U2T_\omega(z')\)
若\(-2^{\omega}\leq z < -2^{\omega-1}\),則\(z'=z+2^\omega\),因此\(0\leq z' < 2^{\omega -1}\),故\(z''=z'\)
其余三種情況以此類推
- 補碼加法溢出判斷:“正+正=負”或者“負+負=正”
補碼的非
- 定義:對於滿足\(Tmin\leq x \leq Tmax\)的\(x\)
\[ -_\omega^tx=\begin{cases} Tmin &x = Tmin\-x & x>Tmin \end{cases} \]
- 根據位級表示計算補碼的非:
- 各位取反再加1:-5=[1011], [0100] + [0001] = [0101] = 5
- 將符號位(包含符號位)與最後一個1之間的位取反:5=[0101], [1011] = -5
無符號乘法
- 定義:\(x*_\omega^uy=(xy)\mod 2^\omega\)
補碼乘法
- 定義:\(x*_\omega^t y=U2T_\omega({(xy)\mod 2^\omega})\)
- 無符號和補碼乘法的位級等價性
給定長度為\(\omega\)的位向量\(\vec x, \vec y\),用補碼形式定義的整數為\(x, y\),用無符號定義的整數為\(x', y'\),則:
\[
T2B_\omega(x*_\omega^t y) = U2B_\omega(x'*_\omega^u y')
\]
證明
\[
\begin{align}
(x'*y')\mod 2^\omega &= ((x_{\omega -1}2^\omega+x) \cdot (y_{\omega -1}2^\omega + y))\mod 2^\omega\&= (xy)\mod 2^\omega\T2U_\omega(x*_\omega^t y)&=T2U_\omega(U2T_\omega((x\cdot y)\mod 2^\omega))\&= x\cdot y \mod 2^\omega\T2B_\omega(x*_\omega^t y)&=U2B_\omega(T2U_\omega(x*_\omega^t y))\&=U2B_\omega((x\cdot y)\mod 2^\omega)
\end{align}
\]
乘常數
- 乘2的冪:\(x\cdot 2^k = x << k\)
- 乘以常數K:將常數K分解為{0,1}序列,然後通過移位和加法
- 計算\(x\cdot K\)
- 分解K:\(K = [(0...0)(1...1)(0...0)...(1...1)]\)
- 計算:考慮從\(n\)位到\(m\)位(\(n \geq m\))為連續的1,有兩種計算方案:
- \((x<<n) + (x <<(n-1))+...+(x<<m)\)
- \((x<<(n+1)) - (x<<m)\)
除以2的冪
對於無符號數,\(x>>k\)產生數值\(\lfloor x/2^k\rfloor\)
對於有符號數
\(x>0\)時同無符號數
\(x<0\)時,\(x>>k\)產生數值\(\lfloor x/2^k\rfloor\),\((x+(1<<k) - 1)>>k\)產生數值\(\lceil x/2^k\rceil\)
偏置的設計:
註意到$\lceil x/y\rceil = \lfloor (x+y-1)/y\rfloor \(,設\)x = qy+r\(,因此\)\lfloor (x+y-1)/y\rfloor=q+\lfloor(r+y-1)/y\rfloor\(,當\)r\(為0時,後面一項為0,當\)r>0\(時後面為1。取\)y=2^k$,即可得到帶偏置的除法公式
【讀書筆記】CSAPP ch2