浮動小数点数・固定小数点数の説明 と その作成方法やメリデメ をまとめた記事です。
記事の内容に誤りがございましたら、ご指摘頂けますと幸いです。
浮動小数点数
浮動小数点数とは
浮動小数点数はコンピューター内部で利用される小数の表現方式の1つです。
浮動小数点数には2進数浮動小数点数と10進数浮動小数点数がありますが、この記事では2進数浮動小数点数について説明します。
浮動小数点数の標準規格はIEEE754で定義されており、ほぼ全てのシステムがIEEE754に準拠しています。
10進数の値はコンピューター内部では2進数(ビット列)で保持されるため、コンピューター内部で利用される浮動小数点数もビット列です。このビット列は符号部、指数部、仮数部で構成されます。
IEEE754には半精度浮動小数点数、単精度浮動小数点数、倍精度浮動小数点数、四倍精度浮動小数点数の4つが定義されています。
この4つの浮動小数点数は、小数を表現するために使用するビット数が異なります。
指数部に使用するビット数が多いほどより大きい数、あるいは、より小さい数を表現することができ、仮数部に使用するビット数が多いほどより高い精度(つまり、誤差が小さい)で数を表現することができます。多くのプログラミング言語で実装されているのは単精度浮動小数点数と倍精度浮動小数点数です。
単精度浮動小数点数
単精度浮動小数点数は符号部 1ビット
、指数部 8ビット
、仮数部 10ビット
で構成されています。
Java
ではfloat
型が単精度浮動小数点数のデータ型です。
倍精度浮動小数点数
倍精度浮動小数点数は符号部 1ビット
、指数部 11ビット
、仮数部 52ビット
で構成されています。
Java
ではdouble
型が倍精度浮動小数点数のデータ型です。
10進数から単精度浮動小数点数を作成する
抽象的な説明だと分かりくいので、実際に10進数の21.75
から単精度浮動小数点数を作成します。
(1) 10進数を2進数に変換する
21.75 -> 10101.11
(2) 正規化する
y × 2のz乗
の形式に正規化します。
正規化はy
が1以上2未満
となるように行います。つまり、1.xxx
の形式にします。
10101.11 × 2の0乗 -> 1.010111 × 2の4乗
(3) 浮動小数点数のビット列を構成する
符号部
符号部のビットは、0
が正
、1
が負
を表します。
なので、符号部のビットは0
となります。
指数部
指数部のビットは、実際の指数の値に127
を加算した値を使用します。(詳しくはなぜ指数部に127
を加算するのか?を参照してください。)
なので、指数部のビットは131(= 4 + 127)
を2進数に変換した10000011
となります。
仮数部
仮数部のビットは、y
の整数部の値を省略し、小数部の値のみを使用します。
前述した正規化に基づくと、y
の整数部は必ず1
となります。なので、y
の整数部の値が1
なのは自明として、y
の小数部の値のみを保持します。
なので、仮数部のビットは10101110000000000000000
となります。(仮数部の余るビット列は0埋めします。)
【補足】 なぜ指数部に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
が使用された時、それは特殊な値として扱われます。
固定小数点数
固定小数点数とは
固定小数点数もコンピューター内部で利用される小数の表現方式の1つです。
固定小数点数にも2進数固定小数点数と10進数固定小数点数がありますが、この記事では2進数固定小数点数について説明します。
固定小数点数も浮動小数点数と同じくビット列です。符号付き固定小数点数の場合、このビット列は符号部、整数部、小数部で構成されます。
整数部と小数部に使用するビット数は各言語やソフトウェアの実装により異なります。
浮動小数点数では値を指数形式で保持しました。10進数から浮動小数点数を作成する過程でy × 2のz乗
の形式に正規化したかと思います。
しかし、固定小数点数では値を指数形式で保持しません。
正の10進数から固定小数点数を作成する
抽象的な説明だと分かりくいので、浮動小数点数と同じく、実際に10進数の21.75から固定小数点数を作成します。
10進数を固定小数点数に変換する方法も、各言語やソフトウェアの実装により異なると思いますが、ここでは代表的な方法を説明します。
まず、正の10進数から固定小数点を作成する方法から説明します。
負の10進数から固定小数点数を作成する方法も後ほど説明しますが、符号ビットを反転することに加えて、整数部と小数部を2の補数とする必要があります。
(1) 10進数を2進数に変換する
21.75 -> 10101.11
(2) 固定小数点数のビット列を構成する
符号部
符号部のビットは、0
が正
、1
が負
を表します。
なので、符号部のビットは0
となります。
整数部
整数部のビット列を構成します。
ビット列が余る場合、ビット列の左を0埋めします。
小数部
小数部のビット列を構成します。
ビット列が余る場合、ビット列の右を0埋めします。
負の10進数から固定小数点数を作成する
次に、負の10進数から固定小数点を作成する方法を説明します。
10進数の-21.75から固定小数点数を作成します。21.75から作成した固定小数点数を用いて作成します。
前述したように、負の10進数から固定小数点を作成する際は、符号ビットを反転することに加えて、整数部と小数部を2の補数とする必要があります。
(3) 符号ビットを反転する
符号ビットを反転します。
(4) 整数部と小数部を2の補数とする
2の補数を作成するには、全てのビット列を反転し、最後にそのビット列へ1を足します。
まず、ビット列を全て反転します。
次に、反転したビット列へ1を足します。
【補足】 補数とは
補数とは、元の数に足すと桁上がりする数のうち一番小さい数(基数の補数)、あるいは、元の数に足しても桁上がりしない数のうち一番大きい数(減基数の補数)のことを指します。
上記を踏まえて、2の補数とは、2進数において、元の数に足すと桁上がりする数のうち一番小さい数(基数の補数)のことを指します。
また、2進数において、元の数に足しても桁上がりしない数のうち一番大きい数(減基数の補数)のことを1の補数と呼びます。
浮動小数点数に対する固定小数点数のメリット・デメリット
Javaなどの多くの言語で、何も考えないまま小数を扱うコードを記述すると、ほとんどの場合、その小数は浮動小数点数として扱われていると思います。
私は、あえて、浮動小数点数ではなく、固定小数点数を使用するべきケースを仕事で経験したことがないのですが、固定小数点数には主に以下のメリデメがあるようです。
メリット
- ① 演算処理が高速である
- ② 誤差が発生しにくく、発生し得る誤差の範囲も予測しやすい
デメリット
- ① 非常に大きい数、あるいは、非常に小さい数を表現することができない