単精度浮動小数点数

情報処理において、単精度浮動小数点数 (Single precision floating point number) は、コンピュータの数値表現の一種である。 浮動小数点形式の標準であるIEEE 754では、単精度は32ビット（4オクテット）、倍精度は64ビット（8オクテット）である。IEEE 754-2008 では単精度の形式は正式には binary32 と呼ばれている。「単」や「倍」という表現は32ビットを1ワードとする32ビットアーキテクチャを基にしている。 単精度浮動小数点数は、同じ幅の固定小数点数に比べてより広範囲な数値を表せるようになっているが、同時に精度を犠牲にしている。 C言語、C++、C#、Java、Haskellでは単精度のデータ型を float と呼び、Pascal、MATLABなどでは single と呼ぶ。3.2以前のOctaveでは single という名前だが倍精度である。Pythonの float も倍精度である。 IEEE 754 での binary32 の定義は次の通りである。 符号ビット: 1ビット 指数部の幅: 8ビット 仮数部の幅: 23ビット 符号ビットは表現する数値の符号（正負）を示す。指数部は 8 ビットで、符号なし整数として見た場合は 0 から 255 の値をとり、0 の時はゼロか非正規化数であることを、1 から 254 の時は -127 のゲタ履き（バイアス付き）表現で -126 から 127 の指数を、255 の時は無限大または NaN であることを示す。 指数部が 0（ゼロ、および非正規化数）の場合を除き、仮数部で表現されるビットパターンのさらにひとつ上のケタに暗黙の 1 のビットがあるとみなす表現法（いわゆる「ケチ表現」）により、通常の数（正規化された数）の精度は、24ビット相当である。従って十進に換算したとき表現できる桁数は log10(224) ≈ 7.225 桁となる。標準化されたレイアウトは以下のようになる。 符号ビットを sign、バイアスつきの指数部を e、23ビットの仮数部の各ビットを b-n とすると、32ビットの binary32 フォーマットで表される数値は ( − 1 ) s i g n ( 1. b − 1 b − 2 . . . b − 23 ) 2 × 2 e − 127 {\displaystyle (-1)^{sign}(1.b_{-1}b_{-2}...b_{-23})_{2}\times 2^{e-127}} となり、より正確に表現すると v a l u e = ( − 1 ) s i g n ( 1 + ∑ i = 1 23   b i 2 − i ) × 2 ( e − 127 ) {\displaystyle value=(-1)^{sign}(1+\sum _{i=1}^{23}\ b_{i}2^{-i})\times 2^{(e-127)}} となる。 単精度バイナリ浮動小数点数の指数部はオフセット表現を使って符号化されており、指数値がゼロのときのオフセット値（バイアス値）は127である。 Emin = 01H−7FH = −126 Emax = FEH−7FH = 127 指数部バイアス = 7FH = 127 指数部バイアスは、エクセスNとも言う。詳しくは符号付数値表現を参照されたい。真の指数値は、指数部の値から指数部バイアスを引いた値となる。 00H と FFH は予約された指数値である。 従って、全てのビットパターンが符号として意味がある。正の最小値（非正規化数）は 2−149 ≈ 1.4 × 10−45 である。正の正規化数の最小値は 2−126 ≈ 1.18 × 10−38 である。表現可能な最大値は (2−2−23) × 2127 ≈ 3.4 × 1038 である。 IEEE754 では実数値から対応する binary32 フォーマットへの変換を丸めも含めて厳密に定めている。 ここでは十進の実数値から IEEE 754 binary32 フォーマットへの変換は大まかに次のようになる。 実数値を 12.375 のように整数部と小数部で表すものとする。 整数部を二進法で表現したものに変換する。 小数部を以下に示す技法で変換する。 2つの変換結果を組み合わせ、さらに変換を加えて最終的な表現を得る。 小数部の変換: 12.375 の小数部 0.375 を例とする。これを二進の小数に変換するため、小数部に2をかけて整数部をとり、さらに2をかけて整数部をとるというように繰り返していき、小数部がゼロになるか精度の上限である二進23桁になるまで続ける。 0.375 x 2 = 0.750 = 0 + 0.750 ⇒ b−1 = 0 となるので、二進での小数部の一桁目はゼロとなる。そこでさらに 0.750 に2をかける。 0.750 x 2 = 1.500 = 1 + 0.500 ⇒ b−2 = 1 0.500 x 2 = 1.000 = 1 + 0.000 ⇒ b−3 = 1 となり、小数部が 0.000 となったのでここで変換は停止する。 これで (0.375)10 は正確に二進で (0.011)2 で表されることがわかった。十進で有限桁数の小数が必ず二進で有限桁で表せるわけではない。例えば、十進の 0.1 は二進では正確に表現できないため近似値を用いることになる。 したがって、(12.375)10 = (12)10 + (0.375)10 = (1100)2 + (0.011)2 = (1100.011)2 となる。 IEEE 754 binary32 フォーマットでは、値を ( 1. x 1 x 2 . . . x 23 ) 2 × 2 e {\displaystyle (1.x_{1}x_{2}...x_{23})_{2}\times 2^{e}} という形式で表現しなければならないので、1100.011 をシフトして整数部が一桁になるようにしなければならない。この例では3桁シフトするので ( 1.100011 ) 2 × 2 3 {\displaystyle (1.100011)_{2}\times 2^{3}} となる。 最終的に ( 12.375 ) 10 = ( 1.100011 ) 2 × 2 3 {\displaystyle (12.375)_{10}=(1.100011)_{2}\times 2^{3}} となる。 この結果から次が得られる。 指数部は 3 となる（バイアスを加えるので実際は 130 = 1000 0010 となる）。 仮数部は 100011 となる（小数点より右側だけを仮数とする）。 したがって、IEEE 754 binary32 フォーマットで 12.375 を表すと 0-10000010-10001100000000000000000 = 41460000H となる。 注: 68.123 を IEEE 754 binary32 フォーマットで表す場合を考えてみよう。上述の技法を適用すると 42883EF9H というビット列が得られ、最後の4ビットは 1001 となる。しかし、IEEE 754 のデフォルトの丸め方式により最終的に 42883EFAH となり、最後の4ビットは 1010 となる。 例: 十進の1を変換すると ( 1 ) 10 = ( 1.0 ) 2 × 2 0 {\displaystyle (1)_{10}=(1.0)_{2}\times 2^{0}} となる。ここから次のことが導かれる。 指数は 0 である（バイアスを加えるので 127 = 0111 1111 となる）。 仮数は 0 である（小数点より右側はゼロなので仮数部のビット列は全てゼロになる）。 従って実数 1 を IEEE 754 binary32 フォーマットで表すと 0-01111111-00000000000000000000000 = 3f800000H となる。 例: 0.25 を変換すると、 ( 0.25 ) 10 = ( 1.0 ) 2 × 2 − 2 {\displaystyle (0.25)_{10}=(1.0)_{2}\times 2^{-2}} となる。ここから次のことが導かれる。 指数は -2 である（バイアスを加えるので 127+(−2)= 125 = 0111 1101 となる）。 仮数は 0 である（小数点より右側はゼロなので仮数部のビット列は全てゼロになる）。 従って実数 0.25 を IEEE 754 binary32 フォーマットで表すと 0-01111101-00000000000000000000000 = 3e800000H となる。 例: 0.375 を変換すると、 0.375 = ( 1.1 ) 2 × 2 − 2 {\displaystyle 0.375={(1.1)_{2}}\times 2^{-2}} となる。ここから次のことが導かれる。 指数は -2 である（バイアスを加えるので 127+(−2)= 125 = 0111 1101 となる）。 仮数は 1 である（1.1 の小数点より右側は 1 = x1 のみである）。 従って実数 0.375 を IEEE 754 binary32 フォーマットで表すと 0-01111101-10000000000000000000000 = 3ec00000H となる。 浮動小数点数値のビット列を十六進法で表した例を以下に示す。これには符号、バイアスを加えた指数値、仮数値が含まれている。 3f80 0000 = 1 c000 0000 = -2 7f7f ffff ≒ 3.4028234 x 1038 (単精度浮動小数点数の正の最大値) 0000 0000 = 0 8000 0000 = -0 7f80 0000 = 正の無限大 ff80 0000 = 負の無限大 3eaa aaab ≒ 1/3 1/3 は倍精度とは異なり、切り上げられる。これは仮数部のビット数が偶数であるため、丸める桁位置以降が 1010... となってその桁位置で 1/2 より大きくなるためである。 16進の値 41c80000 を例として変換を行う。これを二進で表すと次のようになる。 41c8 000016 = 0100 0001 1100 1000 0000 0000 0000 00002 これを、符号ビット、指数部、仮数部の3つに分割する。 符号ビット: 0 指数部: 1000 00112 = 8316 = 131 仮数部: 100 1000 0000 0000 0000 00002 = 48000016 ここで仮数部に暗黙の整数ビットを加える。 仮数: 1100 1000 0000 0000 0000 00002 = C8000016 指数部の値から127を引いて実際の指数値を得る。 指数部の値: 8316 = 131 本来の指数: 131 − 127 = 4 24ビットの仮数は最上位ビットが1に対応し、次の桁が0.5、その次が0.25というように、前の桁の1/2に対応している。 bit 23 = 1 bit 22 = 0.5 bit 21 = 0.25 bit 20 = 0.125 bit 19 = 0.0625 . . bit 0 = 0.00000011920928955078125 この例では、仮数で立っているビットは bit 23、bit 22、bit 19 の3ビットだけであり、上記の対応する値を加算することで十進での仮数が得られる。 本来の仮数: 1 + 0.5 + 0.0625 = 1.5625 = C80000/223 基数 2 を指数値でべき乗したものを仮数にかけると本来の値が得られる。 1.5625 × 24 = 25 従って 41c8 0000 = 25 となる。これは次の式と等価である。 n = ( − 1 ) s × ( m 2 − 23 ) × 2 x − 127 {\displaystyle n=(-1)^{s}\times (m2^{-23})\times 2^{x-127}} ここで s {\displaystyle s} は符号ビット、 x {\displaystyle x} は指数部、 m {\displaystyle m} は仮数を基数10で表したものである。 MSX-BASICの演算ルーチンMATHPACKの場合、同様に4バイトで表すが、IEEE 754とは異なり s(符号ビット): 1 y(指数部の幅): 7 x(仮数部の幅): 24 syyy yyyy xxxx xxxx xxxx xxxx xxxx xxxx であり、指数部をバイナリ、仮数部をBCDで表現する。 そのため、有効数字は正確に10進で6桁で、指数は±63乗である。 同時期の8ビットパソコンのBASICでは、多くがBCDではなく2進での演算であった（十進で計算すると誤差がない、などといった主張が大変しばしば見られるが、1.0/3.0 が正確に計算できないのは十進でも同様であり大変な誤解である。十進計算と二進計算の得失はそれぞれあるので、一概にどちらが優れているなどとは言えるものではない）。 ^ http://java.sun.com/docs/books/tutorial/java/nutsandbolts/datatypes.html 半精度浮動小数点数 (16bit) 単精度浮動小数点数 (32bit) 倍精度浮動小数点数 (64bit) 拡張倍精度浮動小数点数 (80bit) 四倍精度浮動小数点数 (128bit) IEEE 754 浮動小数点数 プリミティブ型 数値的安定性 Online calculator Online converter for IEEE 754 numbers with single precision Online converter Decimal to binary IEEE 754r Half Precision floating point converter : IEEEの倍精度・単精度・半精度の間での変換を行うCのソースコードがある。 Half-precision floating point in C# : C#で書かれたフリーのHalf-floatライブラリ