たまりば

パソコン・インターネット パソコン・インターネット三鷹市 三鷹市

Excelで浮動小数点数のビットパターン表示
2015年06月07日 20:51

Excel関数で浮動小数点数のビットパターンと数値の相互変換を組んでみた。
とりあえず単精度だけ。
Excelで浮動小数点数変換
4b3c614e
=INT(HEX2DEC(LEFT(A1))/8)
=MOD(INT(HEX2DEC(LEFT(A1,3))/8),256)-127
=MOD(HEX2DEC(RIGHT(A1,6)),2^23)
=(A4+2^23)*2^(A3-23)*-1^A2
=A4*2^(-126-23)*(-1^A2)
=IF(A4=0,IF(A2=1,"-∞","∞"),"NaN")
=IF(A3=128,A7,IF(A3=-127,IF(AND(A2=1,A6=0),"-0",A6),A5))
12345678
=IF(A9<0,1,0)
=INT(LOG(ABS(A9),2))
=ABS(A9)/2^(A11-23)-2^23
=ABS(A9)/2^(-126-23)
=IF(A9=0,0,IF(A11>(-127),A12,A13)+(MAX(A11,-127)+127)*2^23+A10*2^31)
=DEC2HEX(A14,8)
=IF(A9="-0","80000000",IF(A9="∞","7F800000",IF(A9="-∞","FF800000",IF(A9="NaN","7F800001",A15))))

使い方

上の式をコピーして、ExcelのA1セルに1行目が合うように貼り付ける。
Excelを持ってない人はLibreOfficeのCalcとかGoogleSpreadSheetとかGnumericとかお好きな表計算ソフトで。Excel固有の機能は特に使っていないのでどれでも動いた。
でもOpenOfficeのcalcは関数の区切りが","じゃなく";"だからそのままだと動かない。","を全部";"に置換すれば動いたけど面倒なのでおすすめしない。
あとGnumericもそのまま貼り付けたらテキスト扱いになっちゃっていちいち先頭の「'」を消さないといけなかったのでおすすめしない。
他に表計算ソフトって何かあったっけ。KingSoftOfficeは試していないけどMSOfficeとの互換性を売りにしてるし大丈夫だろう。
そういえばEeePC買った時にKingSoftOfficeのライセンスついてきたんだよな…。なんか結局使わずじまいだったなあ。
あとは…「ThinkFreeてがるOffice」ってなんか急に思い出したぞ。
…話がそれた。
貼り付けたら、A1セルに単精度浮動小数点数のビットパターンを16進8桁で入力するとA8セルに対応する数値が出る。
逆に、A9セルに数値を入れるとビットパターンがA16セルに出る。

入力は大文字小文字問わず。
出力はExcelで数値として扱えるものは数値で出力。
数値として扱えない-0、±無限大、NaNは文字で出力。
NaNのビットパターンは複数あるが、区別せず「NaN」と出力。

入力は数値として扱えるものは数値で、そうでないものは文字列で。
出力の16進数は大文字。NaNはどれが一般的なのか分からなかったので一番小さい7F800001にしてみた。

解説

それぞれの式で何をしているかを説明する。
=INT(HEX2DEC(LEFT(A1))/8)符号部を取り出す
=MOD(INT(HEX2DEC(LEFT(A1,3))/8),256)-127指数部を取り出し、ゲタ分を補正
=MOD(HEX2DEC(RIGHT(A1,6)),2^23)仮数部を取り出す(ケチ表現はそのまま)
=(A4+2^23)*2^(A3-23)*-1^A2正規化数だった場合の値を符号部と(ケチ表現を補正した)仮数部から計算 ※
=A4*2^(-126-23)*(-1^A2)非正規化数(および0)だった場合の値を符号部と仮数部から計算
=IF(A4=0,IF(A2=1,"-∞","∞"),"NaN")無限大orNaNだった場合の値を符号部と仮数部から計算
=IF(A3=128,A7,IF(A3=-127,IF(AND(A2=1,A6=0),"-0",A6),A5))指数部を見て上3つから適切なものを選択
※特殊値を扱わないなら4行目までだけでOK

=IF(A9<0,1,0)符号部を生成
=INT(LOG(ABS(A9),2))指数部を生成
=ABS(A9)/2^(A11-23)-2^23正規化数だった場合の仮数部を生成
=ABS(A9)/2^(-126-23)非正規化数(および0)だった場合の仮数部を生成
=IF(A9=0,0,IF(A11>(-127),A12,A13)+(MAX(A11,-127)+127)*2^23+A10*2^31)正規化数と非正規化数を場合分けしてまとめる
=DEC2HEX(A14,8)16進数変換
=IF(A9="-0","80000000",IF(A9="∞","7F800000",IF(A9="-∞","FF800000",IF(A9="NaN","7F800001",A15))))-0、±無限大、NaNの場合、直書きの文字列を出力。それ以外は上を出力

おまけ

JavaScriptで組んだら一瞬だった。TypedArrayって便利だね。
そもそもJavaScript自体便利。無限大("Infinity")もNaNも指数表記も扱ってくれる。扱えないのは-0だけかな。
なお動作確認はFirefox(38.0.5, Windows版)でしかしていない。おまけだし。

入力:


出力: