--- tags: sysprog --- # [解讀計算機編碼](https://hackmd.io/@sysprog/rylUqXLsm) ### 編碼發展過程 #### 符號與值 ↓ #### 一補數 - 改良 - 電路設計簡單 - 去掉了「符號」的表示位元,也就代表不需要有獨立電路將MSB分開來判斷,因而簡化電路 - 任何減法運算都可以替換成另一種形式的加法運算 => 不需要專門設計「減法器」,也不需要執行減法那繁瑣的借位運算 - 運用 : 網路封包完整性檢查 (一補述檢驗,最早應用於網際網路前身的 ARPAnet。到了現代為了向下兼容考量,依然是採用這種檢驗方法 ) ↓ #### 二補數 - 改良 - 不用「循環進位」(end-around carry) 在一補數中,如果進行運算後有溢位,須在和的基礎上再加上進位,也就是又多了一次電路運算 ``` 二進位 十進位 11111110 -1 + 00000010 +2 ............ ... 1 00000000 0 <-- 錯誤答案 1 +1 <-- 加上進位 ............ ... 00000001 1 <-- 正確數值 ``` - 改良 - 0的表示法唯一 在一補數裡,$0$ 分為 $+0$ (`00000000`) 和 $-0$ (`11111111`),而二補數就只剩下$+0$ (`00000000`) 這個唯一的表示法。 如此最大的好處,並不是數值表示範圍又多了一個空位 ... 而是「判斷是否為0」的運算成本減半 : 不然原本電路需要進行+0、-0的比較後才能確定一數是否真不為0 ``` if(x != 0x00 && x != 0xff) {...} ``` 改良 : 不用循環進位、`0`的表示法從2種變成1種 (「判斷是否為0運算」成本減半) ### 二補數編碼原理 首先將`0`設定為`00000000`,則`1`會變成`00000001`、`2`變成`00000010`,以此類推 ... 至於`-1`如何表示 ? 我們知道$(-1) + 1 = 0$,且我們已經確定`0`和`1`的編碼,所以 `x + 00000001 = 00000000`,也就是說,`x`為`11111111` 而`-2`呢? 因為$(-2) + 1 = -1$,而從剛才推算的`-1`,我們可以再推算出`-2`為`11111110`,`-3`、`-4` 等等亦是同理。 ### 處理器指令和數值編碼的關係 如上述所說,數值早在一補數時期就已經沒有正負號之分了,但是C語言裡面還是有 有 / 無 號數的型態之分,這除了是轉換成十進位(或字元etc...)給人看以外,也是給少數處理器指令看的。 因為有些時候一數值是正、是負會影響到處理器指令的行為,比如 : 把原本儲存在8bit位元的某數,搬移到16bit位元的新位址。這時就得先知道此數值到底是正還是負,而不能亂轉移。 比如 : `1001101`怎麼移植? 如果是正數,代表$91$,則移植後要變成`00000000 1001101`,$91→91$ ; 如果是負數,代表$-51$,則移植後要是 `11111111 1001101`,$-51→-51$。 可以想見,如果搬移時正負號搞錯,則 $91$ 有可能就變成了 $-51$,這顯然不符合我們對「搬移」的行為預期。