浮動小数点数と固定小数点数について

浮動小数点数・固定小数点数の説明 と その作成方法やメリデメ をまとめた記事です。

記事の内容に誤りがございましたら、ご指摘頂けますと幸いです。

## 浮動小数点数

### 浮動小数点数とは

浮動小数点数はコンピューター内部で利用される小数の表現方式の１つです。

浮動小数点数には**2進数浮動小数点数**と**10進数浮動小数点数**がありますが、この記事では2進数浮動小数点数について説明します。

浮動小数点数の標準規格は**IEEE754**で定義されており、ほぼ全てのシステムがIEEE754に準拠しています。

10進数の値はコンピューター内部では2進数（ビット列）で保持されるため、コンピューター内部で利用される浮動小数点数もビット列です。このビット列は**符号部**、**指数部**、**仮数部**で構成されます。

IEEE754には**半精度浮動小数点数**、**単精度浮動小数点数**、**倍精度浮動小数点数**、**四倍精度浮動小数点数**の４つが定義されています。

この４つの浮動小数点数は、小数を表現するために使用するビット数が異なります。

<font color="MediumVioletRed">
指数部に使用するビット数が多いほど<strong>より大きい数、あるいは、より小さい数を表現する</strong>ことができ、仮数部に使用するビット数が多いほど<strong>より高い精度（つまり、誤差が小さい）で数を表現する</strong>ことができます。
</font>

多くのプログラミング言語で実装されているのは単精度浮動小数点数と倍精度浮動小数点数です。

### 単精度浮動小数点数

単精度浮動小数点数は```符号部 1ビット```、```指数部 8ビット```、```仮数部 10ビット```で構成されています。

```Java```では```float```型が単精度浮動小数点数のデータ型です。

![スクリーンショット 2024-11-02 13.52.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/8384d3fb-7ae1-90c6-fbdb-bfad68e5d6d5.png)

### 倍精度浮動小数点数

倍精度浮動小数点数は```符号部 1ビット```、```指数部 11ビット```、```仮数部 52ビット```で構成されています。

```Java```では```double```型が倍精度浮動小数点数のデータ型です。

![スクリーンショット 2024-11-02 14.02.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/9620d54c-fddc-c2d6-f0a4-8d59ca1d2301.png)

### 10進数から単精度浮動小数点数を作成する

抽象的な説明だと分かりくいので、実際に10進数の```21.75```から単精度浮動小数点数を作成します。

#### (1) 10進数を2進数に変換する

```
21.75 -> 10101.11
```

#### (2) 正規化する

```y × 2のz乗```の形式に正規化します。

正規化は```y```が```1以上2未満```となるように行います。つまり、```1.xxx```の形式にします。

<font color="MediumVioletRed">
指数形式にすることで、<strong>非常に大きい数、あるいは、非常に小さい数の表現が可能になります</strong>。これが後ほど説明する固定小数点数に対する浮動小数点数のメリットです。
</font>

```
10101.11 × 2の0乗 -> 1.010111 × 2の4乗
```

#### (3) 浮動小数点数のビット列を構成する

##### 符号部

符号部のビットは、```0```が```正```、```1```が```負```を表します。

なので、符号部のビットは```0```となります。

![スクリーンショット 2024-11-04 17.47.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/81a6cb9a-cd49-60a4-4cf8-5cb89fca654c.png)

##### 指数部

指数部のビットは、実際の指数の値に```127```を加算した値を使用します。（詳しくは[なぜ指数部に```127```を加算するのか？](https://qiita.com/ohchan/items/deed337a026df50b86e5#%E8%A3%9C%E8%B6%B3-%E3%81%AA%E3%81%9C%E6%8C%87%E6%95%B0%E9%83%A8%E3%81%AB127%E3%82%92%E5%8A%A0%E7%AE%97%E3%81%99%E3%82%8B%E3%81%AE%E3%81%8B)を参照してください。）

なので、指数部のビットは```131(= 4 + 127)```を2進数に変換した```10000011```となります。

![スクリーンショット 2024-11-04 17.54.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/5100bd8c-54c5-036e-c27f-c53fef7c8cc0.png)

##### 仮数部

仮数部のビットは、```y```の整数部の値を省略し、小数部の値のみを使用します。

前述した正規化に基づくと、```y```の整数部は必ず```1```となります。なので、```y```の整数部の値が```1```なのは自明として、```y```の小数部の値のみを保持します。

なので、仮数部のビットは```10101110000000000000000```となります。（仮数部の余るビット列は0埋めします。）

![スクリーンショット 2024-11-04 17.55.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/319c1d78-acdc-118d-2f52-73f8f10379ea.png)

#### 【補足】 なぜ指数部に```127```を加算するのか？

指数部は負の値も表現する必要があります。

例えば、10進数の```0.75```を2進数に変換して正規化すると、```1.1 × 2の-1乗```となります。

```
0.75 -> 0.11
```

```
0.11 × 2の0乗 -> 1.1 × 2の-1乗
```

浮動小数点数自体の正負は符号ビットを使用して表現しますが、指数部の正負は**イクセス表現**（**げたばき表現**）で表現します。

イクセス表現は、表現可能な値の範囲の真ん中の値を```0```とする表現方法です。

指数部は```8ビット```なので、```0から255(2の8乗 - 1)```の値を表現できます。浮動小数点数の指数部では```127```を実際の```0```に対応する値として扱います。

そこで、実際の値からイクセス表現の指数部の値へ変換するためのバイアスとして```127```を加算します。

|変換||||||||||
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|実際の値|特殊|-126|...|-1|0|1|...|127|特殊|
|↓||||||||||
|バイアス|+127|+127|+127|+127|+127|+127|+127|+127|+127|
|↓||||||||||
|指数部の値|0|1|...|126|127|128|...|254|255|

ただし、指数部の値として```0```と```255```が使用された時、それは特殊な値として扱われます。

## 固定小数点数

### 固定小数点数とは

固定小数点数もコンピューター内部で利用される小数の表現方式の１つです。

固定小数点数にも**2進数固定小数点数**と**10進数固定小数点数**がありますが、この記事では2進数固定小数点数について説明します。

固定小数点数も浮動小数点数と同じくビット列です。符号付き固定小数点数の場合、このビット列は**符号部**、**整数部**、**小数部**で構成されます。

整数部と小数部に使用するビット数は各言語やソフトウェアの実装により異なります。

![スクリーンショット 2024-11-24 16.05.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/81281d2f-3cc7-3479-aaad-7cf24c10b816.png)

浮動小数点数では値を指数形式で保持しました。10進数から浮動小数点数を作成する過程で```y × 2のz乗```の形式に正規化したかと思います。

しかし、固定小数点数では値を指数形式で保持しません。

### 正の10進数から固定小数点数を作成する

抽象的な説明だと分かりくいので、浮動小数点数と同じく、実際に10進数の21.75から固定小数点数を作成します。

10進数を固定小数点数に変換する方法も、各言語やソフトウェアの実装により異なると思いますが、ここでは代表的な方法を説明します。

まず、正の10進数から固定小数点を作成する方法から説明します。

負の10進数から固定小数点数を作成する方法も後ほど説明しますが、符号ビットを反転することに加えて、整数部と小数部を**2の補数**とする必要があります。

#### (1) 10進数を2進数に変換する

```
21.75 -> 10101.11
```

#### (2) 固定小数点数のビット列を構成する

##### 符号部

符号部のビットは、```0```が```正```、```1```が```負```を表します。

なので、符号部のビットは```0```となります。

![スクリーンショット 2024-12-01 14.10.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/17220034-0457-2316-1dd0-e335694acfbb.png)

##### 整数部

整数部のビット列を構成します。

ビット列が余る場合、ビット列の左を0埋めします。

![スクリーンショット 2024-12-01 14.12.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/c6341d92-d62d-a0ab-bfd6-9fee88c45548.png)

##### 小数部

小数部のビット列を構成します。

ビット列が余る場合、ビット列の右を0埋めします。

![スクリーンショット 2024-12-01 14.14.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/18512707-c322-2625-4490-0cc277a2cf02.png)

### 負の10進数から固定小数点数を作成する

次に、負の10進数から固定小数点を作成する方法を説明します。

10進数の-21.75から固定小数点数を作成します。21.75から作成した固定小数点数を用いて作成します。

前述したように、負の10進数から固定小数点を作成する際は、符号ビットを反転することに加えて、整数部と小数部を**2の補数**とする必要があります。


#### (3) 符号ビットを反転する

符号ビットを反転します。

![スクリーンショット 2024-12-01 14.59.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/870621bd-e9ec-ac8a-9be4-fe4b265682c1.png)

#### (4) 整数部と小数部を2の補数とする

2の補数を作成するには、全てのビット列を反転し、最後にそのビット列へ1を足します。

まず、ビット列を全て反転します。

![スクリーンショット 2024-12-01 15.02.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/0821db0e-c04c-7a1f-f8a2-279ee238ca91.png)

次に、反転したビット列へ1を足します。

![スクリーンショット 2024-12-01 15.05.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520459/63501022-6bf1-d6af-41e0-32eba73ba237.png)


#### 【補足】 補数とは

補数とは、元の数に足すと桁上がりする数のうち一番小さい数（基数の補数）、あるいは、元の数に足しても桁上がりしない数のうち一番大きい数（減基数の補数）のことを指します。

上記を踏まえて、2の補数とは、2進数において、元の数に足すと桁上がりする数のうち一番小さい数（基数の補数）のことを指します。

また、2進数において、元の数に足しても桁上がりしない数のうち一番大きい数（減基数の補数）のことを1の補数と呼びます。

## 浮動小数点数に対する固定小数点数のメリット・デメリット

Javaなどの多くの言語で、何も考えないまま小数を扱うコードを記述すると、ほとんどの場合、その小数は浮動小数点数として扱われていると思います。

私は、あえて、浮動小数点数ではなく、固定小数点数を使用するべきケースを仕事で経験したことがないのですが、固定小数点数には主に以下のメリデメがあるようです。

### メリット
- ① 演算処理が高速である
- ② 誤差が発生しにくく、発生し得る誤差の範囲も予測しやすい

### デメリット
- ① 非常に大きい数、あるいは、非常に小さい数を表現することができない

## 参考記事
- [float型の限界 / Qiita](https://qiita.com/y-yoshinari/items/76260f6359d5b4418b33)
- [固定小数点数とは？意味をわかりやすく解説 / trends. by CodeCamp](https://trends.codecamp.jp/blogs/media/terminology287)