## 進位制、二進位存儲與運算 ### 12/22 社課 --- ## 進位制 ---- $n$ 進位 $=$ 在這個進位制有 $n$ 種數字符號 $=$ 每 $n$ 個數要進位一次 $n$ 被稱為底數(基數) 通常 $n$ 為自然數 ---- $n$ 進位中的 $a_3a_2a_1a_0$ $=a_3\times n^3+a_2\times n^2+a_1\times n^1+a_0\times n^0$ 要說明某個數是 $n$ 進位 會用$(數字)_n$ 如果 $n$ 超過 $10$,通常會接續使用大寫英文字母 ---- $10$ 進位中的 $2373$ 可以表示為 $2373_{10}$ $=2\times 10^3+3\times 10^2+7\times 10^1+3\times 10^0$ $16$ 進位中的 $2C5B$ 可以表示為 $2C5B_{16}$ $=2\times 16^3+12\times 16^2+5\times 16^1+11\times 16^0$ ---- ### 不同進位的數字念法 $1010$ 這個數字在十進位中念作「一千零一十」 但在其他進位中沒有十百千的念法 因此要讀作「一零一零」 ---- ### 各種進位轉十進位 剛剛其實就看過了 $abcd_n$ $=(a\times n^3+b\times n^2+c\times n^1+d\times n^0)_{10}$ ---- ### 十進位轉各種進位 假設我們要把 $2373_{10}$ 轉成 $8$ 進位 可以不斷除以 $8$ 直到商為 $0$ 為止 得到的餘數由後往前排就是答案 ---- $2373\div 8=296\cdots 5$ $296\div 8=37\cdots 0$ $37\div 8=4\cdots 5$ $5\div 8=0\cdots 5$ 因此我們可以得到 $2373_{10}=5505_8$ ---- 我們可以這麼思考 當 $2373$ 除以 $8$ 得到的商可以被 $8$ 整除 也就是之前看到轉十進位時有乘上 $8$ 的部分 而得到的餘數就是最後剩下的 $\times 8^0$ 以此類推 ---- ### 不同進位之間的轉換 先轉成十進位再轉一次就好了 ---- ### 小數部分 一樣的 $n$ 進位中的 $ab.cd_n$ $=a\times n^1+b\times n^0+c\times n^{-1}+d\times n^{-2}$ ---- 小數轉換時可能會出現循環小數 $1.1_3=1\times 3^0+1\times 3^{-1}=1.\overline3_{10}$ $0.3_{10}=0.01\overline{0011}_2$ (可以想想怎麼算) 由此可知,電腦在計算小數時會有誤差 ---- #### 小知識 所有二進分數$\frac{p}{2^a}$,$p, a\in N$ 都可以化為有限二進位小數(或整數) ---- #### 小知識 2 電腦中儲存顏色的方法 最常用RGB三原色各細分為256種色源 利用 $16$ 進位儲存 \#FF00FF 意思就是R:FF、G:00、B:FF --- ## 二進位在電腦中的儲存 ---- 電腦儲存的最小單位稱作「位元(bit)」 每個位元都可以表示為 $0$ 或 $1$ ---- $8$ 個 bit 稱為 $1$ byte(位元組) $1024$ byte 稱為 $1$ KiB $1024$ KiB 稱為 $1$ MiB $1024$ MiB 稱為 $1$ GiB $1024$ GiB 稱為 $1$ TiB ---- C++中 int 為 $4$ byte,即 $32$ bit,故可以存 $2^{32}$ 種數 long long 為 $8$ byte,可存 $2^{64}$ 種數 ---- #### int 儲存大概長這樣 00000000 00000000 00000000 00001010 表示 $9$ 00000000 00101001 10000100 01000100 表示 $2720836$ ---- ## 存負數? ### 補數與二補數 ---- 假設現在有 $2^k$ 種數可以存(即 $k$ 位元) 相當於我們可以存 $[0, 2^k-1]$ ---- 若想要存負數 我們可以把一半分給非負整數 一半分給負整數 也就是 $[0, 2^{k-1}-1]$ 分給非負整數 剩下的 $[2^{k-1}, 2^k-1]$ 都分給負整數 ---- 我們讓某個 $a\in [2^{k-1}, 2^k-1]$ 表示為一個負數 $a^{\prime}$ 則我們讓 $a^{\prime}=$ 在模 $2^k$ 下與 $a$ 同餘的最大負數 即 $a^{\prime}=a-2^k$ 相當於把 $[2^{k-1}, 2^k-1]$ 映射到 $[-2^{k-1}, -1]$ 這樣我們就可以處理 $[-2^{k-1}, 2^{k-1}-1]$ 的範圍了 ---- #### 補數 對一個數 $b$ 的補數定義為 $2^k-1-b$ 也就是將 $b$ 中的 $0$ 與 $1$ 互換 0001 1110 $\rightarrow$ 1110 0001 1001 0100 $\rightarrow$ 0110 1011 C++ 中可以用 ~b 表示 b 的補數 ---- #### 二補數 對一個數 $b$ 的二補數定義為 $2^k-b$ 即補數加上 $1$ 若進位時超出 $k$ 位元的範圍,則把最高位捨去 0000 0001 $\rightarrow$ 1111 1111 0110 1001 $\rightarrow$ 1001 0111 **0000 0000 $\rightarrow$ 0000 0000** ---- $x$ 的二補數就會是在 $[2^{k-1}, 2^k-1]$ 的 $2^k-x$ 而前面提到這個數代表的就是 在模 $2^k$ 下與其同餘的最大負數 也就是 $(2^k-x)-2^k=-x$ ---- ### 結論 儲存 $x$ 的負數 $-x$ 的方式 就是存它的二補數 ---- ### 至於浮點數儲存? 那個有點複雜 有興趣可以查查看 --- ## 位元運算 ### (bitwise operation) ---- ### <<、>>(左移、右移) 最開始看到這個符號是 cin、cout 的時候 在符號兩邊都是整數時 ```cpp= a << n; ``` 意思是 $a$ 的位元向右移 $n$ 位 ---- ```cpp= int a=10, n=3, ans; ans=(a<<n); //ans=80 ``` 如果 $a=10, n=3$ $a$ 的二進位儲存是 00000000 00000000 00000000 00001010 經過運算後會變成 00000000 00000000 00000000 01010000 ---- 發現到整體會左移 $n$ 個位元 左邊超出部分會捨棄 右邊新的部分會補 $0$ \>> 右移符號也是相同道理,位元會向右移動 ---- 其實也可以注意到 a << n 代表 $a\times 2^n$ 運算時間比直接做乘法來的快 ---- ### ~、&、|、^ 分別為 \~ bitwise not & bitwise and | bitwise or ^ bitwise xor ---- not 前面講過了,就是算補數 實際運算就是對於每個位元去做 and、or、xor 運算 ---- 7&9 $\rightarrow$ 1 7|9 $\rightarrow$ 15 7^9 $\rightarrow$ 14 可以自己練習看看
{"description":"type: slide","title":"12/22 C++社課","contributors":"[{\"id\":\"1a0296c8-ce58-4742-acda-22c02ae81a74\",\"add\":3669,\"del\":342}]"}
    96 views