バイナリ形式の浮動小数点数を10進数表記へ変換するスクリプト
https://gyazo.com/0f4160f3920628fbb4e753e905839530
自作CPUへ組み込む予定のFPU(浮動小数点演算装置)の動作確認をしてるんだけど、FPUとやりとりする値が「IEEE 754 Binary32形式(最近のコンピュータの浮動小数点内部形式はほぼ IEEE 754形式)」の浮動小数点数なので、返ってきた結果が正しいのか正しくないかがパッと見で分からない(0x3F800000が10進数表記でいくつか分かります?答えは 1.0です) しょうがないのでバイナリ形式の浮動小数点数を10進数表記に変換するスクリプトを書いた。使い方はこんな感じ。
code:shell
# 正の数
$ ruby bin2float.rb 11000010111011010100000000000000
-118.625
# 負の数
$ ruby bin2float.rb 01000010111011010100000000000000
118.625
# ゼロ
$ ruby bin2float.rb 00000000000000000000000000000000
0
# 非正規化数(0ではないけれどBinary32で表現できないぐらい小さい値)
$ ruby bin2float.rb 00000000010000000000000000000000
2.2250738585072014e-308(Float::MINが返る)
# 無限大
$ ruby bin2float.rb 01111111100000000000000000000000
Infinity
# NaN
$ ruby bin2float.rb 01111111100000000000000000000001
NaN
# アンダーバーで区切ってもOK
$ ruby bin2float.rb 0_10000101_11011010100000000000000
118.625
# 16進数表記もOK
$ ruby bin2float.rb 42ED4000
118.625
ソースはこんな感じ。
code:bin2float.rb
# bin2float
class Binary32
def initialize(bin32_str)
# セパレータ _ を取り除く
str = bin32_str.gsub(/_/, '')
if str.size == 8
# 16進数表記の場合は2進数表記へ変換
str = "%032b" % str.to_i(16)
end
raise 'Invalid Binary32 string' unless str.size == 32
# 0バイト目は符号(+ or -)
# 1〜8バイト目は指数部
@exp = Exponent8.new(str1..8) # 9〜32バイト目は仮数部
@fract = Fraction23.new(str9..) end
def to_f
# ゼロ
return 0 if @exp.to_i == 0 && @fract.to_f == 0
# 非正規数
return Float::MIN if @exp.to_i == 0 && @fract.to_f != 0
# 無限大
return Float::INFINITY if @exp.to_i == 255 && @fract.to_f == 0
# NaN
return Float::NAN if @exp.to_i == 255 && @fract.to_f != 0
# 符号が0ならプラスの値、1ならマイナス
sign = @sign == "0" ? 1 : -1
# 仮数部を求める際に省略した1.0を戻す
fract = @fract.to_f + 1
# 指数部を求める際に足したバイアス(127)を引く
exp = @exp.to_i - 127
sign * fract * (2 ** exp)
end
end
# 指数部の8bit
class Exponent8
def initialize(exp_str)
@exp = exp_str
end
def to_i
@exp.to_i(2)
end
end
# 仮数部の23bit
class Fraction23
def initialize(fract_str)
@fract = fract_str
end
def to_f
# (b0 * 0.5) + (b1 * 0.25) + (b2 * 0.125) + (b3 * 0.0625) + ...
@fract.split(//).map(&:to_i).zip(1..23).map {|b, n|
b * (2 ** (n * -1)).to_f
}.sum
end
end
p Binary32.new(ARGV0).to_f 参考