# 2. 進位制 *Positional notation*
###### tags: `DLD-VHDL-kl` `中文`
[TOC]
---
## 2.1 進位制

| English | 中文 |
|---|---|
| number | 數字
| digit | `台` 數位 `中` 數碼
| radix | `台` 數基 `中` 底數
| position |
| index |
|二進制<br>binary|八進制<br>octal|十進制<br>decimal|十六進制<br>hexadecimal|
|:---:|:---:|:---:|:---:|
| $11100_2$ | ${34}_8$ | $28_{10}$ | $1\text{C}_{16}$
|十進制|十六進制|
|:-:|:-:|
|$10_{10}$|$\text{A}_{16}$|
|$11_{10}$|$\text{B}_{16}$|
|$12_{10}$|$\text{C}_{16}$|
|$13_{10}$|$\text{D}_{16}$|
|$14_{10}$|$\text{E}_{16}$|
|$15_{10}$|$\text{F}_{16}$|
## 2.2 進位制轉換法
* $n$ 進位無號**整數**
* 最右邊位元稱為[最低有效位元](https://zh.wikipedia.org/wiki/%E6%9C%80%E4%BD%8E%E6%9C%89%E6%95%88%E4%BD%8D)(least significant bit,LSB)
* 最左邊位元稱為[最高有效位元](https://zh.wikipedia.org/wiki/%E6%9C%80%E9%AB%98%E6%9C%89%E6%95%88%E4%BD%8D)(most significant bit,MSB),
* $n$ 進位無號浮點數
#### 轉換方法
* 轉換成10進位的方法——用權值(weight)來加權
下式中,紅色的乘冪就是權值。
* 例1:$110.11_2 = \left(1\times\color{red}{2^2} + 1\times\color{red}{2^1} + 0 \times \color{red}{2^0} + 1\times\color{red}{2^{-1}}+ 1\times \color{red}{2^{-2}}\right)_{10} = 6.75_{10}$
* 例2:$3\text{B}4\text{F}_{16} = \left(3\times\color{red}{{16}^{3}} + 11\times\color{red}{{16}^{2}} + 4\times\color{red}{{16}^{1}} + 15\times\color{red}{{16}^{0}}\right)_{10} = 15183_{10}$
* 由10進位轉換成 $n$ 進位制的方法
> 對於整數部分,重複「除以 $n$,取餘數為數碼,取商」,直到商為零。
> 對於整數部分,重複「乘以 $n$,取整數部分為數碼,取小數部分」,直到小數部分為零。
* 例1:$18.3125_{10} = 10010.01001_2$
```
-- 整數部分
18 / 2 = 9 ... "0" -- LSB
9 / 2 = 4 ... "1"
4 / 2 = 2 ... "0"
2 / 2 = 1 ... "0"
1 / 2 = 0 ... "1" -- MSB,商為零,結束
-- 小數部分
0.3125 * 2 = 0.6250 -- 整數部分 "0" = 小數點後第1位,取小數部分 "0.6250" 繼續算
0.6250 * 2 = 1.2500 -- 整數部分 "1" = 小數點後第2位,取小數部分 "0.2500" 繼續算
0.2500 * 2 = 0.5000 -- 整數部分 "0" = 小數點後第3位,取小數部分 "0.5000" 繼續算
0.5000 * 2 = 1.0000 -- 整數部分 "1" = 小數點後第4位,小數部分為零,結束
```
* 例2:$54.171875_{10} = \text{36.2C}_{16}$
```
-- 整數部分
54 / 16 = 3 ... "6" -- LSB
3 / 16 = 0 ... "3" -- MSB,商為零,結束
-- 小數部分
0.171875 * 16 = 2.75 -- "2" = 小數點後第1位
0.750000 * 16 = 12.00 -- "12" = 小數點後第2位,小數部分為零,結束
```
## 2.3 補數(Complements)
電腦科學中**補數**(complement)的概念類似代數中的相反數(opposite)或加法反元素(additive inverse),可以細分為兩種。
對於 $b$ 進制下的 $n$ 位數 $y$ 而言,
* $\boxed{b^n - y}$
* 稱為 ==$y$ 的 **數基補數**(radix complement)==,
* 或者稱為 ==$y$ 關於 $b$ 的補數($b$'s complement)==。
* 這就相當於每一個數位都用 $(b-1)$ 去減,整個數再加 $1$。
* $\boxed{(b^n - 1) - y}$
* 稱為 ==$y$ 的 **縮減數基補數**(diminished radix complement)==,
* 或者稱為 ==$y$ 關於 $(b-1)$ 的補數($(b-1)$'s complement)==。
* 這就相當於每一個數位都用 $(b-1)$ 去減。[^縮減數基補數的證明]
兩種補數的關係為
* 縮減數基補數 $=$ 數基補數 $-\ 1$
* 數基補數 $=$ 縮減基數補數 $+\ 1$
### 十進制的例子
十進位數 的 縮減數基補數 就是 ==關於 $9$ 的補數==(9's complement)。簡單來說,是==每一個數位都用 $9$ 去減==,比如 $9$ 跟 $0$ 互換,$8$ 跟 $1$ 互換,以此類推。
* $9_{10}$ 關於 $9$ 的補數為 $(10 - 9 - 1)_{10} = 0_{10}$
* $5_{10}$ 關於 $9$ 的補數為 $(10 - 5 - 1)_{10} = 4_{10}$
* $873_{10}$ 關於 $9$ 的補數為 $(10^3 - 873 - 1)_{10} = 126_{10}$
十進位數 的 數基補數 就是 ==關於 $10$ 的補數==(10's complement)。簡單來說,就是它==關於 $9$ 的補數加 $1$==。 例如,
* $9_{10}$ 關於 $10$ 的補數為 $(10 - 9 )_{10} = 1_{10}$
* $5_{10}$ 關於 $10$ 的補數為 $(10 - 5)_{10} = 5_{10}$
* $873_{10}$ 關於 $10$ 的補數為 $(10^3 - 873 )_{10} = 127_{10}$
### 二進制的例子
二進位數 的 縮減數基補數 就是==關於 $1$ 的補數==(1's complement),中文簡稱==一補數==。簡單來說,就是對每一位進行「[位元反相操作](https://zh.wikipedia.org/wiki/%E4%BD%8D%E6%93%8D%E4%BD%9C#%E5%8F%96%E5%8F%8D%EF%BC%88NOT%EF%BC%89)」(bitwise NOT),或者說==讓 $1$ 跟 $0$ 互換==。
例如,
* $1010_2$ 的一補數為 $(10000 - 1010 - 1)_2 = 0101_2$
* $0110_2$ 的一補數為 $(10000 - 0110 - 1)_2 = 1001_2$
二進位數的 數基補數 就是==關於 $2$ 的補數==(2's complement),中文簡稱==二補數==。簡單來說,就是它的==一補數加 $1$==。
例如,
* $1010_2$ 的二補數為 $(10000 - 1010)_2 = 0110_2$
* $0110_2$ 的二補數為 $(10000 - 0110)_2 = 1010_2$
::: spoiler 參考資料
* [維基百科-補數](https://zh.wikipedia.org/wiki/%E8%A1%A5%E6%95%B0)
* [一補數與二補數](https://noob.tw/complements/)
:::
## 2.4 有號數的處理
前面處理的數值都只限於正數;如果要同時處理負數,就要引入**有[符]號數**(signed numbers)的概念,例如有號整數(signed integer)$-129$、有號浮點數(signed float)$-3.14$。
不過電腦只會用二進位數來儲存數值,所以要依靠三種方法來將有號數「編碼」為二進位數。
1. **符號數值表示法**(sign-magnitude representation),又稱原碼(true form),它指定:
* ==最高有效位(MSB)為**符號位元**(sign bit)==,用來表示正、負號。
* 符號位元為 $0$ 表示正號($+$),例如 $\color{red}{0}010_2$ 表示十進位正數 $\color{red}+2_{10}$。
* 符號位元為 $1$ 表示負號($-$),例如 $\color{red}{1}010_2$ 表示十進位負數 $\color{red}-2_{10}$。
* 其他位表示**大小**(magnitude),例如 $0\color{blue}{010}$ 和 $1\color{blue}{010}$ 代表的大小都是 $\color{blue}{010}_2 = 2_{10}$。
2. **一補數式**(1's complement form)是==把 $y_2$ 的一補數當成 $y_{10}$ 的相反數==。例如,
* $0010_2$ 表示十進位正數 $\color{red}+2_{10}$。
* $1101_2$ 表示十進位負數 $\color{red}-2_{10}$。
3. **二補數式**(2's complement form)是==把 $y_2$ 的二補數當成 $y_{10}$ 的相反數==。例如,
* $0010$ 表示十進位正數 $\color{red}+2_{10}$。
* $1110_2$ 表示十進位負數 $\color{red}-2_{10}$。
下表比較三種表示法的差異,其中第一欄是「一個位元組的二進位整數」(one-byte binary integer),其他欄的都是第一欄所代表的十進位整數,省略用來表示進位制的下標。
| 二進位 | 無號數 | 有號數<br><font size=1>符號及大小式</font> | 有號數 <br><font size=1>一補數式</font> | 有號數 <br><font size=1>二補數式</font> |
|:-:|:-:|:-:|:-:|:-:|
| $0000\ 0000$ | $0$ | $+0$ | $+0$ | $0$ |
| $0000\ 0001$ | $1$ | $1$ | $1$ | $1$ |
| $\vdots$ | $\vdots$ | $\vdots$ | $\vdots$ | $\vdots$ |
| $0111\ 1110$ | $126$ | $126$ | $126$ | $126$ |
| $0111\ 1111$ | $127$ | $127$ | $127$ | $127$ |
| $1000\ 0000$ | $128$ | $\color{red}{-0}$ | $-127$ | $-128$ |
| $1000\ 0001$ | $129$ | $-1$ | $-126$ | $-127$
| $\vdots$ | $\vdots$ | $\vdots$ | $\vdots$ | $\vdots$ |
| $1111\ 1110$ | $254$ | $-126$ | $-1$ | $-2$ |
| $1111\ 1111$ | $255$ | $-127$ | $\color{red}{-0}$ | $-1$ |
|表示法|表示的數值範圍(十進位)|
|--|--|
| 符號及大小式 | $-127,\;-126,\;\ldots,\;-1,\;\color{red}{-0},\;+0,\;1,\;\ldots,\;126,\;127$ |
| 一補數式 | $-127,\;-126,\;\ldots,\;-1,\;\color{red}{-0},\;+0,\;1,\;\ldots,\;126,\;127$ |
| 二補數式 | $\color{red}{-128},\;-127,\;-126,\;\ldots,\;-1,\;0,\;1,\;\ldots,\;126,\;127$ |
可以看出,二補數式的範圍多了 $-128$,而「符號及大小式」和「一補數式」則是都產生了「兩種零」:
* 「正零」(positive zero),記作 $+0$。
* 「負零」(negative zero),記作 $-0$。
## 2.5 二進制的算數
### 加法
```
基本規則
0 0 1 1
+ 0 + 1 + 0 + 1
--- --- --- ---
0 1 1 10
^進位
例
(二進制) (十進制)
10110 22
+ 11101 + 29
-------- ----
110011 51
```
### 減法
```
基本規則
0 1 10 1
- 0 - 0 - 1 - 1
--- --- ---- ---
0 1 01 0
^借位
例
(二進制) (十進制)
10110 22
- 1101 - 13
-------- ----
1001 9
```
### 減法(二補數)
==被減數 $+$ **減數的二補數** $=$ 差==
==將任何溢出的最高有效位元捨棄==
```
例1:10110 - 1101 = 1001 (可對照上面「減法」中的例子)
10110
+ 10011 (= 1101 在 5 個位元下的二補數)
---------
1 01001
^溢位,捨棄
例2:0101 1010 - 1101 1011 = 0111 1111
0101 1010
+ 0010 0101 (= 1101 1011 在 8 個位元下的二補數)
-------------
0111 1111
這相當於十進制中的減法 90 - (-37) = 127
例3:1111 1100 - 1110 0111 = 0101 0101
1111 1100
+ 0001 1001 (= 1110 0111 在 8 個位元下的二補數)
-------------
1 0001 0101
^溢位,捨棄
這相當於十進制中的減法 (-4) - (-25) = 21
```
### 乘法
```
基本規則
0 1 0 1
x 0 x 0 x 1 x 1
--- --- ---- ---
0 0 0 1
例1:11 * 10 = 110
(二進制) (十進制)
11 3
x 10 x 2
-------- ----
00 6
+ 11
--------
110
例2: 1011 * 1100 = 1000 0100
(二進制) (十進制)
1011 11
x 1100 x 12
---------------- ------
0000 22
0 000 + 11
10 11 ------
+ 101 1 132
----------------
1000 0100
```
### 除法
```
例1:110 / 11 = 10
(二進制) (十進制)
10 2
------ ----
11 ) 110 3 ) 6
- 11 - 6
------ ----
00 0
- 00
------
00
例2: 1001 1101 / 0110 = 1000 0100
(二進制) (十進制)
0000 1100 12
------------ ------
1101 ) 1001 1100 13 ) 156
- 0000 - 13
------------ -------
1001 1 26
- 0110 1 26
------------ -------
0011 01 0
- 0011 01
------------
00 0000
00 0000
------------
00 0000
```
## 2.6 十六進制的算數
### 加法
```
例:(2BC9 + 50FA)₁₆ = 2BC9₁₆
(十六進制) (十進制)
2BC9₁₆ 11209₁₀
+ 50FA₁₆ + 20730₁₀
---------- ---------
2BC9₁₆ 31939₁₀
(9 + A)₁₆ = (9 + 10)₁₀ = 19₁₀ = 13₁₆,進位
(C + F + 1)₁₆ = (12 + 15 + 1)₁₀ = 28₁₀ = 1C₁₆,進位
(B + 0 + 1)₁₆ = (11 + 0 + 1)₁₀ = 12₁₀ = C₁₆
(2 + 5)₁₆ = (2 + 5)₁₀ = 7₁₀ = 7₁₆
```
### 減法
```
例:(87 - 3D)₁₆ = 4A₁₆
87₁₆ 135₁₀
- 3D₁₆ + 61₁₀
--------- ---------
4A₁₆ 74₁₀
(7 - D)₁₆ = (7 - 13)₁₀ ,不夠減,借位
(17 - D)₁₆ = (23 - 13)₁₀ = 10₁₀ = A₁₆
(8 - 3 - 1)₁₆ = (8 - 3 - 1)₁₀ = 4₁₆
```
亦可換成二進位數之後,用二補數減法。
```
例:(87 - 3D)₁₆ = 4A₁₆
87₁₆ = 1000 0111₂
3D₁₆ = 0011 1101₂
(1000 0111 - 0011 1101)₂ = 0100 1010₂
1000 0111₂
+ 1100 0011₂
------------
1 0100 1010₂
^溢位,捨棄
0100 1010₂ = 4A₁₆
```
[^縮減數基補數的證明]: 證明如下:對於 $b$ 進制下的 $n$ 位自然數 $y = \sum_{k=0}^{n-1}a_kb^k$,其中 $a_k \in \{0,1,\ldots,b-1\}$ 是第 $k$ 個數位,$b^k$ 是第 $k$ 個權數,則 $y$ 的縮減數基補數為 $$\begin{align} \left(b^n - 1\right) - y &= (b-1)\left(b^{n-1} + \cdots + b + 1\right) - y \\ &=(b-1)\left(\sum_{k=0}^{n-1}b^k\right) - \sum_{k=0}^{n-1}a_kb^k \\ &= \sum_{k=0}^{n-1}\left[(b-1)-a_k\right]b^k\end{align}$$ 可見第 $k$ 個數位由 $a_k$ 變成了 $(b-1)-a_k$。