ほとんどのプログラミング言語では、浮動小数点数は指数表記と仮数(仮数とも呼ばれる)を使用して、科学表記法とよく似ています。非常に単純な数は9.2
、実際にはこの部分です:
5179139571476070 * 2 -49
指数-49
と仮数は5179139571476070
です。一部の 10進数をこの方法で表すことができない理由は、指数と仮数の両方が整数でなければならないためです。つまり、すべての浮動小数点数は、整数の2の累乗を掛けた整数でなければなりません。
9.2
は単純かもしれませんが、nが整数値に制限されている場合92/10
、10を2 nとして表すことはできません。
データを見る
まず、32ビットと64ビットを作成するコンポーネントを確認するためのいくつかの関数float
。出力(Pythonの例)のみに関心がある場合は、これらをグロスします。
def float_to_bin_parts(number, bits=64):
if bits == 32: # single precision
int_pack = 'I'
float_pack = 'f'
exponent_bits = 8
mantissa_bits = 23
exponent_bias = 127
elif bits == 64: # double precision. all python floats are this
int_pack = 'Q'
float_pack = 'd'
exponent_bits = 11
mantissa_bits = 52
exponent_bias = 1023
else:
raise ValueError, 'bits argument must be 32 or 64'
bin_iter = iter(bin(struct.unpack(int_pack, struct.pack(float_pack, number))[0])[2:].rjust(bits, '0'))
return [''.join(islice(bin_iter, x)) for x in (1, exponent_bits, mantissa_bits)]
この関数の背後には多くの複雑さがあり、説明するのはかなり正解ですが、興味がある場合、私たちの目的にとって重要なリソースはstructモジュールです。
Python float
は64ビットの倍精度数です。C、C ++、Java、C#などの他の言語では、倍精度には別の型がありdouble
、多くの場合64ビットとして実装されます。
この例を使用して関数を呼び出すと9.2
、次のようになります。
>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']
データの解釈
戻り値を3つのコンポーネントに分割したことがわかります。これらのコンポーネントは次のとおりです。
符号
符号は、最初のコンポーネントに1ビットとして格納されます。説明するのは簡単0
です。フロートが正の数であることを意味します。1
それは否定的であることを意味します。ので9.2
肯定的である、私たちの符号値です0
。
指数
指数は11ビットとして中央のコンポーネントに格納されます。我々の場合には、0b10000000010
。10進数では、それは値を表します1026
。このコンポーネントの癖を使用すると、に等しい数を減算しなければならないことである2 1 - (ビット数) - 1真の指数を取得します。私たちの場合、それは0b1111111111
(10進数1023
)を引いて真の指数0b00000000011
(10進数3)を取得することを意味します 。
仮数
仮数は52ビットとして3番目のコンポーネントに格納されます。ただし、このコンポーネントにも奇妙な点があります。この癖を理解するために、次のように、科学表記法の数を検討してください。
6.0221413x10 23
仮数部は6.0221413
です。科学表記法の仮数は常に1つのゼロ以外の数字で始まることを思い出してください。同じことがバイナリにも当てはまりますが、バイナリには2桁しかありません:0
と1
。だから、バイナリ仮数部は、常にで始まります1
!floatが格納されている場合、1
スペースを節約するために、2進数の仮数の前部は省略されます。真の仮数を取得するには、3番目の要素の前に配置する必要があります。
1.0010011001100110011001100110011001100110011001100110
3番目のコンポーネントに格納されたビットは、実際には、基数ポイントの右側にある仮数の小数部分を表すため、これには単なる加算だけではありません。
10進数を処理するときは、10の累乗で乗算または除算して「小数点を移動」します。2進数では、2の累乗で乗算または除算することで同じことができます。3番目の要素は52ビットなので、その2 52は、それを右に52の場所を移動するには:
0.0010011001100110011001100110011001100110011001100110
10進表記では、これを取得するために除算675539944105574
するのと同じ4503599627370496
です0.1499999999999999
。(これは、正確に2進数で表現できる比率の1つの例ですが、およそ10進数でのみです。詳細については、675539944105574/4503599627370496を参照してください。)
3番目のコンポーネントを小数に変換したので、加算1
すると真の仮数が得られます。
コンポーネントの要約
- 符号(最初のコンポーネント):
0
正、1
負
- 指数(中間部品):減算2 (ビット数)1 - 1 -真の指数を取得します
- 仮数(最後のコンポーネント):2 (ビット数)で
1
割り、真の仮数を取得するために加算します
数の計算
3つの部分をすべてまとめると、次の2進数が与えられます。
1.0010011001100110011001100110011001100110011001100110 x 10 11
これを2進数から10進数に変換できます。
1.1499999999999999 x 2 3(不正確!)
そして、乗算し9.2
て、浮動小数点値として格納された後、()で開始した数値の最終的な表現を明らかにします。
9.1999999999999993
分数として表す
9.2
数値を作成したので、単純な分数に再構成することができます。
1.0010011001100110011001100110011001100110011001100110 x 10 11
仮数を整数にシフトします。
10010011001100110011001100110011001100110011001100110 x 10 11-110100
10進数に変換:
5179139571476070 x 2 3-52
指数を引く:
5179139571476070 x 2 -49
負の指数を除算に変換します。
5179139571476070/2 49
指数を掛ける:
5179139571476070/562949953421312
どちらが等しい:
9.1999999999999993
9.5
>>> float_to_bin_parts(9.5)
['0', '10000000010', '0011000000000000000000000000000000000000000000000000']
すでに仮数は4桁で、その後にゼロがたくさん続くことがわかります。しかし、ペースを見ていきましょう。
バイナリ科学表記を組み立てます。
1.0011 x 10 11
小数点をシフトします。
10011 x 10 11-100
指数を引く:
10011 x 10 -1
2進数から10進数へ:
X 2 19 -1
除算の負の指数:
19/2 1
指数を掛ける:
19/2
等しい:
9.5
参考文献