0

IEEE-754 浮動小数点ビジュアライザ

10進数がIEEE-754のfloat形式でどのように格納されるのか — 符号ビット、指数ビット、仮数ビット — を正確に表示し、0.1のような数値がなぜ正確に格納されないのかを確認できます。

🔒 ブラウザ内で完全に処理されます。ここに入力した内容はアップロードされません。

処理中... 0%
正規化中
指数バイアス計算中
仮数ビット展開中
完了

結果

コンピューターが扱う浮動小数点数 — JavaScriptのnumber、Cのfloat、Pythonのfloat — はすべてIEEE 754に従って同じ形式でエンコードされます。つまり、1ビットの符号、指数部のビット群、仮数部(小数部)のビット群です。単精度(32ビット)は符号1ビット、指数8ビット、仮数23ビットを使い、倍精度(64ビット)はほぼすべての言語で標準の数値型となっている形式で、符号1ビット、指数11ビット、仮数52ビットを使います。このツールは入力された任意の10進数を、どちらのビット幅でもブラウザ組み込みのDataView/ArrayBuffer浮動小数点エンコーダー(実際にコードが動いているのと同じ仕組み)でエンコードし、各ビットをその領域ごとに色分けします。

エンコード自体は3つのステップで進みます。本ツールは最終的なビット列だけを表示するのではなく、それぞれのステップをたどります。まず正規化:数値は1.仮数部 × 2^指数の形に書き直され、2進小数点の左側には0でない桁がちょうど1つだけ存在します(これに満たない小さな数値は非正規化数扱いとなり、暗黙の先行1ビットはありません)。次に指数バイアス:指数フィールドは符号なし整数で正負の指数をともに表現しなければならないため、フィールドに書き込む前に固定のバイアス値(単精度では127、倍精度では1023)が加算されます。3つ目に、仮数部の小数部分をビットごとに展開します。「2を掛けて、整数部分を次のビットとし、残りを保持する」という古典的な手法を、仮数フィールドがいっぱいになるまで繰り返し、あふれたビット群によって結果を切り上げるか切り捨てるかが決まります(IEEE-754デフォルトの最近接偶数丸め)。

これこそが、0.1のようなごく普通の数値が正確に格納されない理由です。2進数では0.1は循環小数(0.0001100110011… と無限に続く)になるため、有限の仮数部では厳密に保持できず、どこかで丸めなければなりません。0.1を32ビットfloatでエンコードしてビットを読み戻すと、0.1ではなく正確に0.100000001490116119384765625が得られます。倍精度はさらに29ビットの仮数部があるため丸め誤差ははるかに小さくなりますが、それでもゼロではありません。64ビットdoubleでの0.1は正確には0.1000000000000000055511151231257827021181583404541015625です。本ツールはこの正確な格納値を任意精度整数演算(浮動小数点の近道を使わない)で計算するため、入力した値とハードウェアが実際に保持する値との差が隠されたり近似されたりすることは決してありません。

特殊な値は通常のエンコードではなく、予約された正確なビットパターンで表現されます。ゼロおよび負のゼロは指数ビットと仮数ビットがすべて0(符号ビットだけが異なります)、±∞は指数ビットがすべて1で仮数ビットがすべて0、NaNは指数ビットがすべて1で仮数ビットの少なくとも1つがセットされます。ここでの処理はすべてブラウザ内でローカルに実行され、入力内容がどこかにアップロードされることは一切ありません。そのため、浮動小数点数にまつわるバグ — ほぼすべてのプログラミング言語で`0.1 + 0.2 !== 0.3`となる理由、グラフィックスコードのfloat32テクスチャではfloat64なら失われない精度が失われる理由、そして金額計算のコードでは一般に2進浮動小数点を避けるべき理由 — に対する本物の直感を安全に養うことができます。