コンピュータで少数点を含む数値を表現するときに浮動小数点数という表現の仕方があります。
その中でも、IEEE(米国電気電子学会)により規格されたIEEE754の浮動小数点数について解説していきます。
基本の浮動小数点数の表現
まず、基本の浮動小数点数の表現の仕方から見てみましょう。
浮動小数点数は「符号」「指数部」「仮数部」の形式で表現します。
32ビットで表現する場合は下記の通りです。
【符号】 【指数部】 【仮数部】 1ビット 7ビット 24ビット
- 符号は正の場合は0、負の場合は1とする
- 指数部は【2^n】で表記する指数nを7ビットの2進数にした値
負の数の場合は2の補数で表現
- 仮数部は正規化した小数点以下の値
仮数部は少数点以下(0.101なら101以降)が入り、指数部は2^-6の-6を7ビットの二進数にした値が入ります。
0 . 10101010 × 2^-6 符号 仮数部 指数部
浮動小数点数形式における正規化とは?
浮動小数点数の仮数部には正規化した値が入りますが、そもそも正規化とは何のことかという話です。
浮動小数点数形式における正規化とは少数点の位置を移動し、最上位の桁を0以外の値にすることを言います。
正規化の例を見てみましょう。
「0.016×10^-2」、「0.00016×10^0」、「0.0016×2^-1 」の数値はどれも同じ数値です。
この数字から小数点の最上位を「0.16^10-3」のように0以外に変えることが正規化です。
0.016 × 2^-2 ⇒ 0.00016 × 2^0 ⇒ 0.36 × 10^-3 0.016 × 2^3 ⇒ 正規化された形式
2進数の場合の浮動小数点数を表現してみる
上記では10進数でしたので2進数の「0.001」を32ビットの浮動小数点数の形式にします。
まずは仮数部を求める
0.001は小数点数の最上位桁が0なので0以外になるようにまずは正規化を行います。
0.001 ↓ 正規化 0.1 × 2^-2
仮数部には正規化した0.1の小数点以下の値を入れます。
24ビットあるので足りない部分は全て0で生めます。
【符号】 【指数部】 【仮数部】 1ビット 7ビット 100000000000000000000000 ←0.1の1を24ビットの枠に入れる()
次に指数部を求める
次に指数部を求めます。
指数部は2^nのnを2進数にした値です。
今回の例だと「0.1 × 2^-2」ですのでnは「-2」と負の数ですね。
なので2の補数を使って7ビットの2進数にします。
0000010 ↓ 1111101 ↓1を加算する 1111110(10進数: -2)
- 2の負の補数にした2進数にすると1111110が求まりました。
指数部にはこの「1111110」を入れます。
【符号】 【指数部】 【仮数部】 1ビット 1111110 ←2の補数表現をした2^-2の【1111110】を入れる。 100000000000000000000000
最後は符号を設定する
最後は符号を設定すれば浮動小数点数の形式が完成します。
符号部は正の数なら0、負の数なら1を設定します。
今回の例の2進数の「0.001」はの正の数なので0を設定します。
【符号】 【指数部】 【仮数部】 0ビット 1111110 100000000000000000000000
完成。
01111110100000000000000000000000 「0.001」を浮動小数点数の形式にしたもの
IEEE754の浮動小数点数
次に「IEEE754」の浮動小数点数形式のやり方をご紹介します。
IEEE754は32ビットの場合、下記のように表現します。
【符号】 【指数部】 【仮数部】 1ビット 8ビット 23ビット
IEEE754が、基本の浮動小数点数形式と違う点は正規化を「1.xx」の形式で正規化します。
2進数の「0.0011」を正規化すると「0.11 × 2^-2」になるところ、IEEE754だと「1.1 × 2^-3」と正規化します。
これで1ビット多く保持できます。
符号、指数部、仮数部は下記のように求めます。
- 符号は正の場合は0、負の場合は1とする
- 指数部は【2^n】で表記する指数nに対して127を足して、2進数表記にした値
負の数の場合は2の補数で表現
- 仮数部は1.XXの形で正規化した小数点以下の値
IEEE754の浮動小数点数に表現してみる
先ほどと同じ「0.001」をIEE754の浮動小数点数にしてみます。
仮数部を求める
まずは仮数部を求めます。
IEEE754の場合は仮数部は1.XXに正規化した値が入ります。
0.001を正規化します。
0.001 ↓ 正規化 1.1 × 2^-3
仮数部には正規化した「1.1」の小数点以下の1が入ります。
足りない部分は全て0で埋めます。
【符号】 【指数部】 【仮数部】 1ビット 8ビット 10000000000000000000000
次に指数部を求める
次に指数部を求めます。
指数部には2^nのnの部分に127のバイアスと呼ばれる値を加算した結果を2進数にした値を入れます。
今回の例だと「1.1 × 2^-3」なので-3に127を加算した値を2進数に変換します。
-3 + 127 = 124 ↓ 01111011
127を加算した結果の「124」を2進数に変換した「01111011」が指数部になります。
【符号】 【指数部】 【仮数部】 1ビット 01111011 10000000000000000000000
最後に符号を求める
最後に符号部を求めます。
2進数の「0.001」は正の数なので0を設定します。
【符号】 【指数部】 【仮数部】 0 01111011 10000000000000000000000
完成です。
00111101110000000000000000000000 IEEE754で正規化した「0.001」
浮動小数点数における"誤差"
浮動小数点数では表現できる数の範囲が決まっていて、32ビット形式なら仮数部は24ビット、IEEE754なら23ビットです。
割り切れないような2進数の少数などはこの範囲に収まらないため、それと近い値で表現しますが、その弊害に実際の値と誤差が出てしまいます。
誤差には4種類あります。
種類 | 内容 |
---|---|
丸め誤差 | 表現できる値の範囲を超えた時に有効桁を切り捨てることによって発生する誤差 |
打ち切り誤差 | コンピュータの計算途中で打ち切ることによって発生する誤差 |
桁落ち | 値がほぼ等しい値の差を求めた時に発生する誤差 |
情報落ち | 大きい値と小さい値の数値の和もしくは差を求めた時に発生する誤差 |
丸め誤差は「0.11001100...」と続く無限小数に対して、24ビットで収まるように有効桁以降を捨てることで、正しい結果との間に誤差が発生することです。
打ち切り誤差は「1/3=0.3333333」と続く計算を行う時に、コンピュータが途中で計算を打ち切ることで正しい結果との間に誤差が発生することです。
桁落ちは値がほぼ等しい値と計算することで有効桁数が減少しておきる誤差です。
例えば、「1.2345−1.2344 」を計算すると0.0001となり有効数字が5から1桁に減少することで発生する誤差です。
情報落ちは大きな値と小さい値の加減算を行う際に、小さい値の情報が無視されてしまうことによって生じる誤差です。
例えば、有効桁数が4桁だと、下記の計算を行うと0.12341234となるところ
0.1234 + 0.00001234
有効桁数が4桁なので0.1234となってしまい、値の小さい0.00001234が無視されてしまいます。
さいご
最後まで読んでいただき、ありがとうございました。
もし、記載している内容が間違えていれば遠慮なくコメントしてください!
私自身の勉強になりますし、他の人がこの記事を見た時に間違えた情報を見ることになってしまうので💦
関連記事・オススメ記事
↓オススメ書籍↓
価格:2,860円 |
JavaプログラマGold SE 8 試験番号:1Z0-809 (オラクル認定資格教科書) [ 山本道子(プログラミング) ] 価格:4,620円 |
新人エンジニアのための データベースのしくみと運用がわかる本【電子書籍】[ 五十嵐貴之 ] 価格:2,178円 |