IEEE 754 変換ツール|浮動小数点⇔ビットパターン(32/64ビット)

10進数の小数とIEEE 754ビットパターン(単精度32ビット・倍精度64ビット)を相互変換。符号・指数部・仮数部を色分け表示し、NaN・無限大・非正規化数もひと目で判別できます。

古典的な例: なぜ 0.1 + 0.2 は 0.3 にならないのか

JavaScriptで `0.1 + 0.2` を計算すると `0.30000000000000004` になり、`0.3` とは一致しません。これは倍精度浮動小数点数のビットパターンを見ると理由がわかります。

値 倍精度(64ビット)16進数 倍精度(64ビット)2進数
0.1 0x3FB999999999999A 0011111110111001100110011001100110011001100110011001100110011010
0.2 0x3FC999999999999A 0011111111001001100110011001100110011001100110011001100110011010
0.3 0x3FD3333333333333 0011111111010011001100110011001100110011001100110011001100110011
0.1 + 0.2 0x3FD3333333333334 0011111111010011001100110011001100110011001100110011001100110100

0.1も0.2も0.3も、2進数では無限小数(循環小数)になるため、有限の52ビットの仮数部には収まりきらず丸められます。0.1と0.2の丸め誤差の方向がたまたま一致しないため、両者を足した結果は0.3を正確に表すビットパターンとは1ビットだけ異なる値(0x3FD3333333333334)になります。上の変換ツールで実際にこれらの値を入力し、末尾ビットの違いを確認してみてください。

IEEE 754とは?ビットで見る浮動小数点数

コンピューターが小数を扱うとき、内部では「IEEE 754」という規格に従って符号・指数部・仮数部という3つの区分にビットを割り当てています。このツールは、入力した10進数の値がメモリ上でどのようなビット列として保存されているか(またはその逆)を、単精度(32ビット)・倍精度(64ビット)の両方で可視化します。

普段の開発では意識しなくても、`0.1 + 0.2` が `0.3` にならない、大きな整数を浮動小数点数に入れると誤差が出る、といった現象の裏側にはすべてこのビット表現があります。符号ビット・指数部・仮数部がそれぞれ何を表しているかを実際の数値で確認することで、丸め誤差やNaN・無限大・非正規化数といった特殊な値がなぜ生まれるのかを具体的に理解できます。

使い方

  1. 変換の向きと精度を選ぶ 「10進数→ビットパターン」または「ビットパターン→10進数」を選び、単精度(32ビット)か倍精度(64ビット)かを指定します。
  2. 値を入力する 10進数なら普通の数値のほか"NaN"・"Infinity"・"-Infinity"も入力できます。ビットパターンなら`0x`付き16進数、または選択した精度と同じ桁数の2進数を入力します。
  3. 符号・指数部・仮数部の内訳を確認する 色分けされたビット列と、生の指数値・バイアス除去後の指数値・16進数表記などの詳細を表で確認します。
  4. 分類バッジと補足説明を読む ゼロ・非正規化数・正規化数・無限大・NaNのどれに該当するかが自動判定され、それぞれの意味の説明が表示されます。
  5. プリセットや特殊値で試す 0.1・0.2・0.3・±0・±Infinity・NaNのプリセットボタンや、負の値・極端に大きい/小さい値を入力して挙動を比較します。

使いこなすためのヒント

  • 0.1・0.2・0.3を倍精度でそれぞれビット化し、0.1+0.2の結果(0.30000000000000004)と見比べると、末尾1ビットだけ異なることが視覚的に確認できます。
  • 「-0」を10進数欄に入力すると、符号ビットだけが1になったビットパターン(+0とは異なる)が得られます。数値としては0===-0ですが、ビット表現は別物です。
  • 指数部がすべて0のとき、仮数部が0ならゼロ、0でなければ非正規化数(精度を犠牲にしてゼロに極めて近い値を表す特殊な表現)になります。
  • 単精度(32ビット)と倍精度(64ビット)を切り替えると、同じ0.1という値でも丸め誤差の大きさが異なる(単精度の方が誤差が大きい)ことが確認できます。
  • ビットパターンからの逆変換では、`0x`接頭辞付きの16進数か、選択した精度と同じ桁数の2進数(`0b`接頭辞は任意)で入力する必要があります。

こんな場面で使えます

大学・独学でのコンピューターサイエンス学習

「浮動小数点数の内部表現」を教科書だけでなく実際の数値で確認しながら学べます。授業のレポートや自習の確認用にも使えます。

数値計算バグの原因調査

"なぜこの計算だけ誤差が出るのか"をコードを書かずに、値を入力してビットパターンを見るだけで切り分けられます。

組み込み・低レイヤープログラミングの実務

メモリダンプに現れる16進数の浮動小数点値を、実際の10進数値に逆変換して確認する用途に使えます。

技術面接・資格試験の対策

「単精度と倍精度のビット構成の違いを説明してください」といった定番の出題に対し、実例を見ながら準備できます。

「0.1 + 0.2 ≠ 0.3」を人に説明するとき

口頭の説明だけでは伝わりにくい丸め誤差の仕組みを、実際のビット列を見せながら説明できます。

用語集

IEEE 754
コンピューターにおける浮動小数点数の表現方法を定めた国際標準規格です。1985年に制定され、ほぼすべてのプログラミング言語のfloat/double型がこれに準拠しています。
符号ビット
値が正か負かを表す1ビットです。0なら正、1なら負を意味し、指数部・仮数部が同じでも符号ビットだけが異なる「+0」と「-0」のような区別が生まれます。
指数部
値のスケール(桁の大きさ)を表すビット列です。単精度は8ビット、倍精度は11ビットで構成され、バイアスを加えた形で格納されます。
仮数部(フラクション)
値の有効数字(精度)を表すビット列です。単精度は23ビット、倍精度は52ビットあり、通常は先頭に暗黙の1が付加された状態で解釈されます。
バイアス
指数部を符号なし整数として格納するために加算する固定値です。単精度は127、倍精度は1023で、符号付き整数のような複雑な処理をせずに大小比較できるようにする工夫です。
非正規化数(subnormal)
指数部がすべて0で仮数部が0でないビットパターンです。仮数の先頭の暗黙の1を省略することで、通常表現できる最小値よりもさらにゼロに近い値を、精度を犠牲に表現します。
NaN(非数)
指数部がすべて1で仮数部が0でないビットパターンです。0/0や∞-∞のように数学的に定義できない演算の結果として生成されます。
無限大(Infinity)
指数部がすべて1で仮数部がすべて0のビットパターンです。表現できないほど大きい値になった計算(オーバーフロー)の結果などに現れます。

よくある質問

0.1・0.2・0.3はいずれも2進数では無限に続く循環小数になり、コンピューターは有限桁の仮数部(倍精度なら52ビット)に収めるため途中で丸めます。0.1と0.2それぞれの丸め誤差の方向がたまたま一致しないため、両者を足した結果は0.3を正確に表すビットパターンとわずかに異なる値(0.30000000000000004)になります。これは特定の言語のバグではなく、IEEE 754準拠のすべての言語で共通して起こる現象です。

単精度(float、32ビット)は符号1ビット・指数部8ビット・仮数部23ビット、倍精度(double、64ビット)は符号1ビット・指数部11ビット・仮数部52ビットで構成されます。仮数部のビット数が多いほど有効桁数(精度)が高く、指数部のビット数が多いほど表現できる値の範囲が広くなります。一般的なプログラミング言語の既定の浮動小数点型は倍精度であることが多いです。

指数部がすべて0のビットパターンのうち、仮数部が0でないものを指します。通常の(正規化された)浮動小数点数は仮数の先頭に暗黙の1が付きますが、非正規化数はこれを省略し、代わりに指数を最小値に固定することで、通常表現できる最小値よりもさらにゼロに近い値を表現できます。ただし有効桁数は犠牲になります。

IEEE 754では符号ビットが1ビット独立して存在するため、指数部・仮数部がすべて0でも符号ビットが0なら「+0」、1なら「-0」という2つの異なるビットパターンが生まれます。数値としての比較では0 === -0となり等しいと判定されますが、1/0が+Infinity、1/-0が-Infinityになるなど、演算結果に違いが表れる場合があります。

どちらも指数部がすべて1のビットパターンで表現されます。仮数部がすべて0なら無限大(符号ビットで+Infinity/-Infinityを区別)、仮数部が0でなければNaN(Not a Number、非数)です。0除算や∞-∞のような数学的に定義できない演算の結果として生成されます。
ツールくん

余談ですが ― IEEE 754という「共通言語」ができるまで

1985年以前、コンピューターメーカー各社は独自の浮動小数点数表現を採用していました。IBM・DEC・Crayなど、同じ「0.1」という値を計算しても、計算機が違えば結果の丸め方や表現できる範囲が微妙に異なり、あるマシンで書いたプログラムを別のマシンに移植すると数値計算の結果がわずかに食い違うという問題が常態化していました。この混乱を解消するため、Intel 8087数値演算コプロセッサの設計にも携わったカリフォルニア大学バークレー校のWilliam Kahanらが中心となり、業界横断の標準規格として1985年に「IEEE 754」が策定されました。

IEEE 754の核心的なアイデアは、有限のビット数(32ビットや64ビット)で無限に存在する実数を近似的に表現するにあたり、符号・指数部・仮数部という3つの区分に役割を分担させたことです。指数部が桁の大きさ(スケール)を担当し、仮数部が有効数字の精度を担当することで、非常に小さい数から非常に大きい数まで、限られたビット数でも柔軟に対応できる仕組みになっています。指数部にバイアス(単精度なら127、倍精度なら1023)を足して格納するのは、符号付き整数用の2の補数のような複雑な符号処理をせず、ビット列同士を単純比較するだけで大小関係が判定できるようにするための工夫です。

2進数で「きれいに」表現できる小数は、分母が2のべき乗になる分数(1/2、1/4、3/8など)に限られます。10進数の0.1は分数で書くと1/10ですが、10は2のべき乗ではないため、2進数では0.0001100110011...と無限に続く循環小数になってしまいます。有限桁の仮数部に収めるには途中で打ち切って丸めるほかなく、これが「0.1を正確にコンピューターで表現できない」根本的な理由です。10進数の0.3を10進数の世界で正確に扱いたい会計システムなどが、浮動小数点数ではなく整数演算や専用の10進数型(BCD、decimal型)を使うのはこのためです。

IEEE 754はその後、2008年・2019年に改訂され、半精度(16ビット)や四倍精度(128ビット)、10進浮動小数点数の規定なども追加されましたが、根幹となる符号・指数部・仮数部の3分割構造と丸めモードの考え方は1985年の初版から変わっていません。ほぼすべてのプログラミング言語のfloat/double型がこの規格に準拠しているため、「なぜ0.1+0.2が0.3にならないのか」という疑問は、言語を問わず共通して発生する現象なのです。