エントリー

2010年08月02日の記事は以下のとおりです。

コンピュータ基礎の基礎~浮動小数点の扱いとIEEE754

  • 2010/08/02 20:17
  • カテゴリー:備忘録

 コンピュータ基礎の基礎,今回は浮動小数点演算です。

 一般に,我々がコンピュータを扱うときには,整数で表現が可能な演算が中心です。しかし,コンピュータが計算機である以上,小数点を扱う演算も日常的に起こります。

 Z80のように乗除算さえ持たないCPUを搭載した昔のパソコンでも,浮動小数点演算が出来た事を考えると,整数しか扱えないCPUも,プログラム次第で浮動小数点が扱えることになりますが,このように2進数で浮動小数点演算を行う場合には,その扱い方,つまりフォーマットが非常に重要です。

 かつては,この各社でバラバラだったフォーマットも,IEEE754という国際標準によって統一されており,データフォーマットの違いによるデータ互換のなさなど,不便な点が解消されてきました。

 まず,最初に,2進数で小数点の付いた数をどうやって表現するかです。

 思い出して欲しいのは,2進数というのは2になると桁が上がる数でした。一桁増えるごとに2倍になるのが2進数です。これはいいですね。

 10進法では,桁が増えるごとに10倍になるわけですが,では小数点から以下の桁はどうだったかというと,小数第一位が1/10,小数第二位が1/100と,桁が小さくなるごとに1/10ごとになっていきます。

 2進数でも同じ事で,小数第一位は1/2で0.5,小数第二位は1/4で0.25となっていきます。小数点以下が01なら0.25,10なら0.5,11なら0.75となるわけですね。

 では具体的に,小数点の付いた数を2進数で表現してみましょう。14.75を2進数で表現すると,まず小数点から上である14は1110です。次に小数点以下ですが,0.75から0.5を引き算すると0.25ですので,小数第一位と小数第二位の両方のビットが立ちます。

 よって,14.75は,2進数では1110.11となります。簡単ですね。

 浮動小数点というのは,小数点が動く表現方法です。先程の14.75は,1.475x10の-1乗,というわけですが,このうち1.475を仮数,10を基数,そして-1を指数といいます。これも基本ですね。

 問題はここから先です。この1110.11という0と1の列びを,どうやってメモリに格納するのかです。例えば小数点から上の1110の部分を何ビットで格納すればいいでしょうか。8ビット?10ビット?各社でバラバラだと,そのデータに互換性が出てこないのも頷けます。

 そこで1985年に制定された標準形式がIEEE754です。もう少し見ていきましょう。IEEE754のフォーマットは,以下のようになっています。

(1)基数は2で,基数はデータに含めない。
 基数というのは何の2乗とか3乗かを示す数字でした。IEEE754は2進数を扱うフォーマットですから,基数は2です。わかりきったことなのでいちいちこれをフォーマットには入れません,と言う意味です。

(2)仮数は1以上,2未満に揃える。これを正規化という。
 先程の14.75も,浮動小数点で表現すると1.475x10の-1乗となりました。このことで仮数部は10未満になります。IEEE754でも同じ事で,仮数部を1以上未満で扱う事にします。

(3)0の表現は,指数と仮数の全ビットをゼロにする。
 仮数部を0にすれば絶対にゼロなのですが,IEEE754では仮数部が0で指数部が最大になっているものを∞の表現に割り当てます。ゆえに全ビットゼロとしなければなりません。

(4)仮数も指数も2進数で表現する。
 これもまああたり前の話です。14は1110ですし,0.75は0.11です。

(5)MSBが符号ビットで,0が正,1が負を示す。
 当然正の数も負の数も扱いますので,符号ビットを考えておかねばなりません。MSB,つまり最上位のビットに符号の役割を与えます。

(6)単精度は32ビットで,符号1ビット,指数部8ビット,仮数部23ビットである。0から22ビットまでが仮数部,23から30ビットが指数部,31ビットが符号ビットである。
 IEEE754には単精度と倍精度の2つがありますが,このうち単精度は指数部を8ビット,仮数部を23ビットとしてあります。

(7)単精度の場合は,指数部は実際の指数に127を足し,仮数部は整数部分の1を省略する。
 正規化してあるので,仮数部は必ず1以上2未満になりますから,整数部分の1をわざわざ記述する必要がありません。また,指数部に足される127という数値をバイアス値と言います。バイアスを加えるのは,指数部が負の数を取ることがあるからです。

(8)倍精度は64ビットで,符号1ビット,指数部11ビット,仮数部が52ビットである。0から51ビットが仮数部,52から62ビットが指数部,63ビットが符号ビットである。

(9)倍精度の場合,指数部は実際の指数に1023を足し,仮数部は整数部分の1を省略する。


 ルールとしてはこんな感じです。

 では,2.5を単精度で表現してみましょう。

 まず,2.5を2進数で書きます。2は2進数で10,0.5は2進数で0.1ですから,10.1となります。

 これを正規化します。10.1x2^0ですから,これをシフトし,1.01x2^1とします。ここで,仮数部が1.01,指数部が1,そして基数が2となります。

 仮数部は整数部分を省略しますから,01となります。なお,基数2も省略します。また符号ビットは正ですので0です。

 仮数部は1になりますが,これにバイアス値である0x7fを足し,0x80とします。

 これらから,以下のようになります。

0 10000000 01000000000000000000000


 それでは次に0.1を倍精度で表現してみましょう。

 実はこの0.1をに2進数で正確に表現するのが不可能なのです。

 0.1ですから,0.5よりも,0.25よりも,0.125よりも小さいです。この段階で0.000まで確定です。

0.1-2^(-1)=-0.4  0.0
0.1-2^(-2)=-0.15  0.00
0.1-2^(-3)=-0.025  0.000

 さらにもうヒトケタ小さくしますと,0.0625です。ここでようやく1になり,0.0001です。しかし余りが0.0375でます。

0.1-2^(-4)=0.0375  0.0001

 余りである0.0375を使って以後計算します。

0.0375-2^(-5)=0.00625  0.00011
0.00625-2^(-6)=-0.009375  0.000110
0.00625-2^(-7)=-0.0015625  0.0001100
0.00625-2^(-8)=-0.00234375  0.00011001
0.00234375-2^(-9)=0.000390625  0.000110011
0.000390625-2^(-10)=-0.0005859375  0.0001100110
0.000390625-2^(-11)=-0.00009765625  0.00011001100
0.000390625-2^(-12)=0.000146484375  0.000110011001

 というわけで,ちゃんと証明したわけではありませんが,どうやら00110011・・・手な具合に循環していそうです。これでは永遠に割り切れることはないでしょう。つまり,0.1は2進数でちゃんと表現出来ないということになるのです。

 それはそれとして,先に進みましょう。0.0001100110011・・・を正規化します。1.100110011・・・x2^-4となります。よって仮数部は1.100110011・・・,指数部は-4です。

 指数部は倍精度の時には0x3ffをバイアスとして足します。すると指数部は0x3fbです。そう,指数部が負の数を取ることがあるから,バイアスを足すのでしたね。

 よって,64ビットで表現される倍精度フォーマットでは,以下のようになります。

0 01111111011 1001100110011001100110011001100110011001100110011001・・・

 一見するとこれいいように思いますが,実は循環する数字がそのままカットされているので,決まった範囲に数値が収まるように,丸めを行います。言ってみれば,3.14159・・・とせず,3.14と小数第2位までで表現するのと同じ事です。

 IEEE754では,4つの丸めが定義されています。

・最近接偶数丸め(RN)
 最も近くの表現できる値へ丸めます。基本的には0捨1入としますが,ちょうど中間の場合には,偶数になるよう,つまり仮数部の一番低位の数字が0になるようにします。誤差の蓄積もなく,もっともおすすめの方法です。

・0方向丸め(RZ)
 常に0に近い方に丸めます。いわゆる切り捨てです。

・+∞への丸め(RP)
 正の無限大に近い方に丸めます。

・-∞への丸め(RM)
 負の無限大に近い方に丸めます。

 さて,先程の数字ですが,標準では最近接偶数丸めを使います。入りきらなかった最初の数字は1ですので,これは0に丸めます。つまり,110011は,1000000に丸めます。よって,0.1は倍精度では,

0 01111111011 1001100110011001100110011001100110011001100110011010

 となります。


 この丸めによって,実は,10進数で0.0000000000000000055511151231257827021181583404541015625もの誤差を含んでいることになるわけですが,これがデジタルコンピュータの本質的な問題であるという事です。

ページ移動

  • 前のページ
  • 次のページ
  • ページ
  • 1

ユーティリティ

2010年08月

1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -

検索

エントリー検索フォーム
キーワード

ユーザー

新着画像

新着エントリー

過去ログ

Feed