MENU

Pythonで小数型の数値を2進数、さらには16進数に変換する

Pythonで小数型の数値を2進数に変換するために関数を作ってきましたが、この結果が本当に正しいかは全くわかりません。そこで、小数を2進数に変換する関数やメソッドを探してみましたが現時点で見つかっていません。そのかわり、16進数に変換すること、次のように結果が帰されます。

0.1.hex()
0x1.999999999999ap-4

0.1は2進数にすると仮数部が”11001100110011001100110011001100110011001100110011010″の53桁、指数部が-4となりますが、これでは仮数部がみずらくて仕方ないということで16進数に直すのが一般的です。ここで先ほどのhexメソッドの結果は次のように解釈します。

図のとおり0x.は16進数を表し、仮数部1ビット目(けちビット)だけ2進数で表し、残り52桁は4ビットごとに16進数に変換しています。最後の1010だけ丸め処理で切り上がっているので9(1001)ではなくa(1010)になっています。最後にpowerを表すpの次に指数部の桁数(-4)を記載しています。 ここまで求まれば、小数を2進数に変換するには簡単です。

def hex2bin(h): 
    h=h.hex()
    Bin='1'
    for i in range(4,17):
        Bin+=(format(int(h[i],16),'#06b')[2:6])
       
    return Bin,int(h[19:])    
print(hex2bin(0.625) )
print(hex2bin(0.1) )
('11001100110011001100110011001100110011001100110011010', 4)

Binで2進数の文字列を作っていきますが、1文字目はけちビットなので”1″、それ以降は3桁目から4ビットずつ区切り2進数に変換していきます。int(h[i],16)で文字列を16進数に変換し、format関数で”a=10″を’#06b’の書式で変換するとformat(10,’#06b’)=’0b1010’となります。0bは2進数であることしめし、3桁目から6桁目までが2進数の並びになります。このため、Binで53桁の仮数部を計算し、指数部はそのまま18桁目以降を返すことで2進数への変換は完成です。

逆に2進数から16進数に変換する関数も作りました。

def bin2hex(Bin,bias,digits=13):
    Bin+=(digits*4+1-len(Bin))*'0'
    H=''
    for i in range(digits):
        H += format(int(Bin[4*i+1:4*i+5], 2), 'x')
    return '0x1.'+H+'p'+str(bias)

bin2hex('11001100110011001100110011001100110011001100110011010', -4)
0x1.999999999999ap-4

ここでは、digitsとして仮数部を16進数にした時の桁数をしてすることもできます。倍精度浮動小数点方式では13桁ですが、他の精度でも計算できるようにしています。

この2つの関数があれば、自作で小数を2進数に変換したものとPythonで計算する2進数を比較することができるようになります。

この記事を書いた人

目次