1. 程式人生 > >【讀書筆記】CSAPP ch2

【讀書筆記】CSAPP ch2

兼容 求反 使用 c++ floor 溢出 書寫 asc star

目錄

  • 第二章 信息的存儲和表示
    • 信息存儲
      • 十六進制表示法
      • 字數據大小
      • 尋址和字節順序
      • 字符串的表示
      • 代碼表示
      • 布爾代數
      • 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