BitとOctとHex (高校 - 情報Ⅰ)

一部サボって省略している箇所がありますが、参考程度に読んでみてください

:::note

実教出版の『ベストフィット情報Ⅰ』(2022)の内容に沿った記事となっております
第３章 pp.28-51 の内容です
([citrus_sota](https://qiita.com/citrus_sota/)の記事の再掲となります(同内容です))
:::

### デジタル化とは
アナログデータ(連続的)を2進数 (0 or 1)の離散的な情報に置き換えること
データの基本単位は、`bit`である
8bit = 1B (B = byte)

|日本語|英語|一桁あたり最大bit|数値リテラルのプレフィックス|
|---|---|---|---|
|2進数|binary number|$\log_2(2)=1$|`0b`|
|8進数|octal number|$\log_2(8)=3$|`0o`|
|10進数|decimal number|$\log_2(10)\approx3.32$|
|16進数|hexadecimal number|$log_2(16)=4$|`0x`|

なお、*n* bitで表現できる状態は、$2^n$ 通りである

|名前|単位|2進数接頭語|10進数接頭語(SI接頭語)|
|---|---|---|---|
|キロ|k|$2^{10}$|$10^3$|
|メガ|M|$2^{20}$|$10^6$|
|ギガ|G|$2^{30}$|$10^9$|
|テラ|T|$2^{40}$|$10^{12}$|
|ペタ|P|$2^{50}$|$10^{15}$|
|エクサ|E|$2^{60}$|$10^{18}$|
|ゼタ|Z|$2^{70}$|$10^{21}$|
|ヨタ|Y|$2^{80}$|$10^{24}$|

2007年に、2進数接頭語の場合を特別に *IEC 60027-2* によって単位の横にiをつけた`Ki`, `Mi`, `Gi`, `Ti`, `Pi`, `Ei`, `Zi`, `Yi`という単位が作られたが、未だ普及しておらず、困惑しやすい状態となっている
なお、基本的にはメモリー演算など特殊な場合を除いてSI接頭語の$10^n$の規格が用いられることが多い

### 0以上の整数 (符号なし)
ここでは、二進数表記は8bitが上限とする

|10進数|0b~~~~~~~~|0o~~~~|0x~~~~|
|---|---|---|---|
|0|0b00000000|0o000|0x00|
|1|0b00000001|0o001|0x01|
|2|0b00000010|0o002|0x02|
|3|0b00000011|0o003|0x03|
|4|0b00000100|0o004|0x04|
|5|0b00000101|0o005|0x05|
|6|0b00000110|0o006|0x06|
|7|0b00000111|0o007|0x07|
|8|0b00001000|0o010|0x08|
|9|0b00001001|0o011|0x09|
|10|0b00001010|0o012|0x0a|
|11|0b00001011|0o013|0x0b|
|12|0b00001100|0o014|0x0c|
|13|0b00001101|0o015|0x0d|
|14|0b00001110|0o016|0x0e|
|15|0b00001111|0o017|0x0f|
|16|0b00010000|0o020|0x10|
|17|0b00010001|0o021|0x11|
|:|:|:|:|
|254|0b11111110|0o376|0xfe|
|255|0b11111111|0o377|0xff|
|**256**|0b**1**00000000|0o400|0x100|

先述の通り、ここでは2進数表記の上限を8bitと定義しているため、256を2進数で表現しようとすると`0b100000000`となり、`OverflowError`が発生する
#### エラー一覧
1. 桁溢れ誤差
    1. オーバーフロー (Overflow)　: 定義bitの最大値を上回る時
    1. アンダーフロー (Underflow) : 定義bitの最小値を下回る時
1. 桁落ち
    ほぼ同じ数の差を求めるときに発生する (浮動小数点の場合のみしか発生しない) 
    [浮動小数点](#浮動小数点)
1. 丸め誤差
    bit列を超えた分を切り上げや切り捨てすることによって発生する誤差
1. 打ち切り誤差
    無限小数や無理数の演算を途中で打ち切ることによる誤差
1. 情報落ち
    大きい値と小さい値の和または差を求めるときに生じる誤差

#### 練習問題
(1) : 8bit型で表せる最大の10進数は何か答えなさい
<details><summary>答え</summary>

```
255
```
</details>
(2) : 16bitで表せる最大の16進数は何か答えなさい
<details><summary>答え</summary>

```
FFFF
```
</details>

(3) : `23`, `42`, `60`をそれぞれ2進数と16進数に変換しなさい

<details><summary>答え</summary>

```
23 / 2進数 : 010111, 16進数 : 17
42 / 2進数 : 101010, 16進数 : 2A
60 / 2進数 : 111100, 16進数 : 3C
```
</details>

(4) : 10進数の`100`を表すのに最低限必要な2進数bit数を答えなさい
<details><summary>答え</summary>

```
7 bit
```
</details>

(6) : 16進数の`1A7`を10進数に変換しなさい
<details><summary>答え</summary>

```
423
```

</details>

(7) : 2進数の`10101010`を16進数で表しなさい
<details><summary>答え</summary>

```
AA
```
</details>

(8) : 16進数の`C0`を2進数で表しなさい
<details><summary>答え</summary>

```
11000000
```

</details>

### 前範囲の整数 (符号あり)
#### 定義
ここでは、`符号あり8bit整数` を扱うが、どのような形式になるかは状況によるため、気をつけてもらいたい
|符号|$2^6$|$2^5$|$2^4$|$2^3$|$2^2$|$2^1$|$2^0$|10進数|
|---|---|---|---|---|---|---|---|---|
|**O**|**v**|**e**|**r**|**f**|**l**|**o**|**w**|128|
|0|1|1|1|1|1|1|1|127|
|0|1|1|1|1|1|1|0|126|
|0|1|1|1|1|1|0|1|125|
|0|1|1|1|1|1|0|0|124|
|:|:|:|:|:|:|:|:|:|
|0|0|0|0|0|1|0|0|4|
|0|0|0|0|0|0|1|1|3|
|0|0|0|0|0|0|1|0|2|
|0|0|0|0|0|0|0|1|1|
|0|0|0|0|0|0|0|0|0|
||||||||||
|1|1|1|1|1|1|1|1|-1|
|1|1|1|1|1|1|1|0|-2|
|1|1|1|1|1|1|0|1|-3|
|1|1|1|1|1|1|0|0|-4|
|1|1|1|1|1|0|1|1|-5|
|1|1|1|1|1|0|1|0|-6|
|1|1|1|1|1|0|0|1|-7|
|:|:|:|:|:|:|:|:|:|
|1|0|0|0|0|0|1|0|-126|
|1|0|0|0|0|0|0|1|-127|
|1|0|0|0|0|0|0|0|-128|
|**O**|**v**|**e**|**r**|**f**|**l**|**o**|**w**|-129||

#### 練習問題

(1) : 以下の各符号あり8bit整数に対して、その10進数の値を答えなさい。
    `0b01010101`, `0b11100000`, `0b10011001`, `0b01111111`, `0b11111110`
<details><summary>答え</summary>
    
```
順に、85, -32, -103, 127, -2
```
</details>

(2) : 16, 32, -16, -32を符号付き8bit整数の2進数表記に直しなさい
<details><summary>答え</summary>

- 16: `0b00010000`
- -16: `0b11110000`
- 32: `0b00100000`
- -32: `0b11100000`
</details>

(3) : なぜ符号付き8bit整数における正の最大値が127なのに対して、負の最小値は-128なのか。訳を述べなさい
<details><summary>答え</summary>

``` chatGPTの答え.txt
符号付き8ビット整数では、最初の1ビットが符号を表し、残りの7ビットが数値を表します。
最初の1ビットが0の場合は正の数を、1の場合は負の数を表します。

具体的に、符号なし8ビット整数の場合、最大値はすべてのビットが1になる255です。
しかし、符号付き8ビット整数では、最初の1ビットが符号を表すため、その1ビットを符号に使うことになります。
残りの7ビットで数値を表すため、その範囲は0から127までの正の整数になります
（0は特別なゼロとして扱われます）。

負の数を表現するためには、最初の1ビットが1になります。
この場合、残りの7ビットで表現できる数値は、0から127の範囲となります。
しかし、この場合、最初の1ビットが符号を表すためのビットになるため、数値の範囲は-128から0までとなります
（-128は最初の1ビットが1の場合の最小の数値として扱われます）。

これにより、符号付き8ビット整数では、正の最大値が127であり、負の最小値が-128である理由が説明されます。
```
以上、chatGPTの答えでした
</details>

### 固定小数点数 (符号なし)
8bit式固定小数点方の場合は、以下の通り
|$2^3$|$2^2$|$2^1$|$2^0$||$2^{-1}$|$2^{-2}$|$2^{-3}$|$2^{-4}$||10進数|
|---|---|---|---|---|---|---|---|---|---|---|
|0|1|0|1||1|1|0|1||5.375|
|1|1|1|1||1|1|1|1||15.9375|

符号ありは省略します (めんどくさくて...)

### 浮動小数点
今回は、32bit式、64bit式 を扱う
### 16bit形式
>符号部 : 1bit
>指数部 : 8bit
>仮数部 : 23bit
>なお、この形式は IEEE754 と呼ばれる規格である

$(10進数) = (2進数).(2進数) = (符号)(2進数A)\times 2^n$

上の式の$2^n$の`n`に対して、バイアス(`n bit`の時、$2^{n-1}-1$)を加えたものを指数部にいれる。
*二進数A* を仮数部に左詰めで並べる。ただし、余った分の桁は`0`で埋める

例 : 
$5.75 = 101.11 = + 1.0111 \times 2^2$

以下の表の`a`は指数部、`b`は仮数部である
符号は、`+`が0, `-`が1である

なお、下の表の`-`は、省略の意味である

|符号|a|a|a|a|a|a|a|a||b|b|b|b|b|b|b|b|-|b|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|0|1|0|0|0|0|0|0|1||0|1|1|1|0|0|0|0|-|0|

よって、5.75 (10進数)は、IEEE754形式に直すと、`01000000101110000...0`

#### 練習問題
(1) : 0.025をIEEE754形式の浮動小数点で表せ
<details><summary>答え</summary>

$0.025 = 0.00000110011001100110011001100... = + 1.10011001100... \times 2^{-6}$
<details><summary>0.025 = の右への直し方</summary>
直したい数を、2倍していき、一度`1`が一の位に出たら、それ以降は少数第一位のみを2倍して、その数字を記録していく

**0**.025
↓
**0**.05
↓
**0**.10
↓
**0**.20
↓
**0**.40
↓
**0**.80
↓ ここで、一度1に達したら、それ以降は少数第一位のみを2倍していく
**1**.6
↓
**1**.2
↓
**0**.4
↓
**0**.8
↓
**1**.6
↓
**1**.2
↓
↓

これ以降は無限に続くため、切り上げ、一の位の数をピックアップする
すると順に、`000000110011`となる。ここで、左から1桁目と2桁目の間に`.`を打つと、`0.00000110011..`となり、答えがもとまった


</details>

バイアス : $-6 + 2^{8-1}-1 = 121$
|符号|a|a|a|a|a|a|a|a||b|b|b|b|b|b|b|b|-|b|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|0|0|1|1|1|1|0|0|1||1|0|0|1|1|0|0|1|.|..|

`00111100110011001100...`が答えとなる

</details>

(2) : $-3.1$をIEEE754形式の浮動小数点で表せ
<details><summary>答え</summary>

$-3.1$から符号`-`を一度取り、3と0.1で分けて考える
`3`について、`0b11`
`0.1`について、
<details><summary>求め方</summary>

**0**.1
**0**.2
**0**.4
**0**.8
**1**.6
**1**.2
**0**.4
**0**.8
**1**.6
**1**.2
**0**.4
**0**.8
**1**.6

</details>

つまり、`0.000110011001100...`となる。
`3`と`0.1`を合わせると、
`11.000110011001100...`
これを正規化すると、
$1.1000110011001100... \times 2^1$
となる。
これを先ほどと同じ手法でバイアスと組み合わせると、

|符号|a|a|a|a|a|a|a|a||b|b|b|b|b|b|b|b|-|-|b|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|1|1|0|0|0|0|0|0|0||1|0|0|0|1|1|0|0|1|1|..|

答えは、$110000000100011001100...$となる。
</details>

***
### 誤差に関する思考問題 
背景説明:
コンピュータで数値を表現する際、二進数が用いられます。しかし、二進数による数値表現には誤差やエラーが含まれることがあります。特に小数を表現する場合、この問題が顕著に現れます。次の問題に答えてください。

問題:
以下の二つの数値について、二進数表記とその10進数表記を比較し、それぞれの誤差について説明しなさい。また、これらの誤差が生じる原因についても詳しく述べなさい。

(1) 2進数表記 : 0.1
(2) 2進数表記 : 0.00011001100110011001100110011001100110011001100110011...
<details><summary>答え</summary>

(1) 0.5
(2) この2進数は、10進数で正確には表せない 0.1 に非常に近い値を表す。
2進数 0.00011001100110011001100110011001100110011001100110011... は周期的に続く無限小数であり、これは10進数で 0.1 に非常に近い 0.1 - ε （εは非常に小さな誤差）になる。
この誤差は、無限に続く二進数を有限のビット数で表現することに起因する。
この場合の誤差`ε`の名称は、**打ち切り誤差**です
</details>

***

Thank you for reading !