浮動小数点数
テンプレート:専門的 浮動小数点数(ふどうしょうすうてんすう、英: floating point number)は、浮動小数点方式による数のことで、もっぱらコンピュータの数値表現において、それぞれ固定長の仮数部と指数部を持つ、数値の表現法により表現された数である。
Contents
概要
指数表現によって可能な十分に広い絶対値の範囲内において、仮数部の桁数に依って常に一定の範囲内の相対誤差で任意の実数を近似できるという特性がある。そのため、極端な数を扱う分野(科学計算など)で多く用いられている。また、プログラミング言語のほとんどが対応しているということもあり、小数の表現方法としては最も普及している。
整数演算と同じ操作で処理が済む固定小数点と違い、通常の整数演算命令を使って実装すると、多くの命令と時間が必要になる。処理の軽減のため、演算にはハードウェアで実装したFPUなどのコプロセッサを用い、現在のマイクロプロセッサなどの多くでは内蔵されていることが多い。
なお、この記事では固定精度の浮動小数点数のみ扱う。任意精度の浮動小数点については任意精度演算を参照のこと。
浮動小数点数の構造
浮動小数点数では次のデータで数値を表現する。
現在広く使われている表現方法ではいずれも基数を固定しており、明示的に符号化しないため、実際に符号化されるのは、次の3つである。
- 符号部(1ビット)
- 仮数部(符号なし整数)
- 指数部(符号付き整数)
浮動小数点数では、数値の絶対値は(仮数部)×(基数)(指数部)となる。たとえば、0.5を浮動小数点数で表すと、基数が10の場合は5.0×10-1(5.0e-1)、基数が2の場合は1.0×2-1となる。
2進法で正規化をすると、最上位ビットは常に1になるので、これを表さず常に1があるものとみなす省略が可能で、省略した表現をケチ表現などと言う。この省略を使うと、仮数部に割り当てたビット数がnであれば、有効桁数はn+1となる。
0を表す場合は符号部、仮数部、指数部のすべてのビットを0とすると都合が良いことからそのようにされることが多い。またその場合は+0.0で、浮動小数点では他に符号部が負をあらわし他が0の-0.0という0もあることがある。たとえば正の数を負の無限大で割ったり、負の数を正の無限大で割ったりすると-0.0になる。
浮動小数点数のフォーマット
浮動小数点数のフォーマットには、以下で説明する次のようなものをはじめとして多数あるが、現在ではほぼ標準であるIEEE 754に収束し、その他は(専用ハードウェアや、特殊用途や研究目的といったものを除き)歴史的な理由で残されているにすぎないものがほとんどである。
- IEEE方式(IEEE 754。最も広く採用されている標準規格)
- IBM方式(IBMのメインフレームおよびそれを模倣した各社の互換マシンで使われていた。指数部を基数16で表現するのが特徴)
- 指数部と仮数部を可変とする方式(これは研究用の面が強い。以下の該当する節で詳述)
IEEE方式(IEEE 754 形式)
IEEE 754 形式の
- 半精度浮動小数点数では、符号部 1 ビット ・ 指数部 5 ビット ・ 仮数部 10 ビット
- 単精度浮動小数点数では、符号部 1 ビット ・ 指数部 8 ビット ・ 仮数部 23 ビット
- 倍精度浮動小数点数では、符号部 1 ビット ・ 指数部 11 ビット ・ 仮数部 52 ビット
- 四倍精度浮動小数点数では、符号部 1 ビット ・ 指数部 15 ビット ・ 仮数部 112 ビット
で表現されている。各部は次のように定義されている。
- 符号部は、 0 を正、1 を負とする
- 仮数部は、整数部分が 1 であるような2進小数の小数部分(ケチ表現)を表す
- 指数部は、符号なし2進整数とし、半精度では 15、単精度では 127、倍精度では 1023、四倍精度では 16383 のゲタを履かせたゲタ履き表現で表す
つまり、IEEE 754 形式で表現する値は
- 半精度の場合: (-1) 符号部×2指数部 ‐15 ×(1+仮数部)
- 単精度の場合: (-1) 符号部×2指数部 ‐127 ×(1+仮数部)
- 倍精度の場合: (-1) 符号部×2指数部 ‐1023×(1+仮数部)
- 四倍精度の場合: (-1) 符号部×2指数部 ‐16383×(1+仮数部)
である。
ただし、IEEE 754 形式の指数部は複雑で、以下のような役割も持つ。
- 通常の浮動小数点数(正規化数)を表現するのは、指数部が単精度で 254 ~ 1(127 ~ -126)、倍精度で 2046 ~ 1(1023 ~ -1022)の範囲のときである
- 指数部が、単精度の場合 255(128)、倍精度の場合 2047(1024)のとき:
- 仮数部が 0 以外の場合は、非数(NaN; Not a Number)を表す
- 仮数部が 0 の場合は、符号部が 0 のときは正の無限大、符号部が 1 のときは負の無限大を表す
- 指数部が 0(単精度の場合 -127、倍精度の場合 -1023)のとき:
- 指数部、仮数部ともに 0 のときは ±0 を表す
0 を 0 で割ろうとすると NaN になる。また、[math]\sqrt{-1}[/math] も、求めるとNaNになる。
IEEE 754 で表現するまでの過程
2.5を例にとると、
- 仮数の符号は、+
- 仮数の絶対値は、2.5
- IEEE 754の基数は、2で固定(簡単のため、以下では省略)
- 指数は、0
であることから、まず次のように考える。
- (-1)0×2.5×20
仮数部は1未満でなければならないため、仮数の値2.5を(この例では右へ)シフトし正規化する。基数は2、コンピュータの内部表現は2進法であるため、シフト量は1ビットである。さらに、右シフトして1⁄2になったことを相殺するため、指数に1を加える(もし左シフトなら、指数から1を引く)。 値をシフトすることで表現範囲を広げ、丸め誤差を少なくなるようにしている。この操作を正規化という。正規化は基数の±1乗を繰り返し求めればよい。
このままでは (-1)0×1.25×21 となり、仮数の絶対値は1未満ではないが、仮数部は 仮数 - 1 と決められているため、次のようになる。
- (-1)0×(1 + 0.25)×21
- 符号部は、0
- 仮数部は、0.25
- 指数は、1
指数部は、指数に127をバイアスすることが決まっているため
- (-1)0×(1 + 0.25)×2(128 - 127)
- 符号部は、0
- 仮数部は、0.25
- 指数部は、128
2進法では、
- 符号部(1ビット):+→0
- 仮数部(23ビット):0.25→.01000000000000000000000
- 指数部(8ビット):128→10000000
浮動小数点は、最上位ビットから符号部、指数部、仮数部の順に符号化するため
- 2進値:0 10000000 01000000000000000000000、16進値:40200000
bfloat16
インテルや Google が採用している IEEE 754 形式に基づく浮動小数点数の形式。符号部 1 ビット ・ 指数部 8 ビット ・ 仮数部 7 ビットである。
つまり、bfloat16 形式で表現する値は
- (-1) 符号部×2指数部 ‐127 ×(1+仮数部)
である。
採用事例
- インテル
- Intel Xeon Cooper Lake マイクロアーキテクチャ以降
- Nervana NNP-L1000
- Google
- Tensor Processing Unit 2.0 以降
IBM方式
IBM方式は、IBM社がSystem/360で導入し、以後同社の標準としてSystem/370などのメインフレームで使った方式である(1994年4月[1]発表のSystem/390では、従来形式のサポートは残すもののIEEE 754を使用するよう改めた)。指数部が2の冪ではなく16の冪を表すという特徴がある。この方式は、より大きな範囲を少ないビット数の指数部で表すことができ、そのぶんのビットを仮数部の桁数に使うことで精度も確保できるように一見思える。しかし、仮数部にケチ表現を使うことができず、さらに指数部の変化の前後で、仮数部のLSBが表現する値の刻み幅が16倍変化するため、2べきの場合に比べて最悪の場合には2進で3ビット分の精度が損なわれるため、一般には大成功であったと評されたSystem/360の設計において良くなかった点の一つとして挙げられる。(浮動小数点数の加減算の際に必要となる仮数部のシフトが4ビット単位となるのでシフト回数が減ることで演算が程度高速になる利点も16進数が採用された理由であった。)
特に単精度において、前世代機のIBM 7094(全部で36ビット)よりも桁数を減らした(32ビット)ことと相まって精度が大きく損なわれた。その他にも問題があり、ユーザグループであるSHAREから改善提案が出され、その多くを受け入れて多大なコストのかかる改修をおこなったほどであり、これを記憶しているIBMの古参社員は「身の縮む思い」をおぼえているという[2]。
また、計算対象の数値がベンフォードの法則に従って分布していた場合、計算対象として精度の低い数(仮数部の最上位4ビットが0b0001)の現れる確率は1/15にはならず、もっと高い[3]。
IBM方式の単精度浮動小数点数では、符号部1ビット、指数部7ビット、仮数部24ビットで表現されている。各部は次のように定義されている。
- 符号部は、0を正、1を負とする
- 仮数部は、1未満の16進小数とする
- 指数部は、16を基数とした指数に64をバイアスした値で表す
符号部は仮数の符号を表す。 指数部は-1663~-16-64と16-64~1663の範囲が表現できる。
IBM方式で表現するまでの過程
1.5を単精度のIBM方式で表現するには、次のようになる。
- (-1)0×1.5×160
仮数部は1未満でなければならないため、値を(この例では右へ)シフトする。ただし、基数が16で、コンピュータの内部表現は2進法であるため、シフト量は4ビットである(24 = 16)。加えて正規化し、その結果は次の通り。
- (-1)0×0.09375×161
次に指数部を、64をバイアスしたゲタ履き表現(エクセス64)で表現する。バイアスにより、0~127のビットパターンで、整数値-64~+63を表現するということになる(-64 + 64 = 0、63 + 64 = 127)。 よって、今回の例では以下のようになる。
- (-1)0×0.09375×16(65 - 64)
2進法では、
- 符号部(1ビット):+→0
- 仮数部(24ビット):0.09375→.000110000000000000000000
- 指数部(7ビット):65→1000001
浮動小数点は、最上位ビットから符号部、指数部、仮数部の順に符号化するため
- 2進値:0 1000001 000110000000000000000000、16進値:41180000
指数部と仮数部を可変とする方式
任意精度演算と、従来の指数部と仮数部を共に固定長とする形式の中庸と言えるような方式が、いくつか提案されている。絶対値が1に近い値では指数部の桁数を短くし、仮数部の桁数を多くとって、よく使われる値を精度よく表現する。絶対値が極端に大きい値や小さい値には、精度とひきかえに指数部の桁数を増やすことで対応する。以下で述べる方式を提案している文献では、アプリケーションとして、通常の浮動小数点計算には、指数が大きくなり過ぎることがあって向かないとされているw:Graeffe's methodをうまく扱えたという例が示されている。
松井・伊理の表現法
松井正一と伊理正夫が提案した方式で、符号と絶対値による表現法である。論文中に示された例では、64ビットの倍精度浮動小数点数として、仮数部の長さnを示す情報6ビットと、(符号部を含む)mビットの指数部とnビットの仮数部(m+n = 58)から成る。彼らは、オーバーフローを起こさせないための、より大きい数やより小さい数の表現や、無限大などの例外的な値を含めた算術(IEEE標準の±∞や-0の扱いに似ているが、より拡張されている)も提案しているが、ここでは割愛する。[4][5]
浜田のURR
浜田穂積が提案した方式[6]で、Universal Representation of Real numbersの意でURRと名付けられている[7]。-∞ ~ 0 ~ ∞ の区間を、次のように分割しながら、二進法による表現に対応付ける、というのが基本的な考え方で、「符号と絶対値」形ではなく、浮動小数点の表現としては比較的珍しい2の補数の形をしている。
- 100 = -∞
- 101 = -2
- 110 = -1
- 111 = -0.5
- 000 = 0
- 001 = 0.5
- 010 = 1
- 011 = 2 ~ ∞
ここで±1の前後は、区間の両端の比が2なので、指数部の表現は終わったとみなすことができ、残りの桁は仮数部のように扱う(±1の前後は、以後は1/2で等差分割する)。次のように分割を続ける。
- 1000 = -∞
- 1001 = -4
- 1010 = -2
- 1011 = -1.5
- 1100 = -1
- 1101 = -0.75
- 1110 = -0.5
- 1111 = -0.25
- 0000 = 0
- 0001 = 0.25
- 0010 = 0.5
- 0011 = 0.75
- 0100 = 1
- 0101 = 1.5
- 0110 = 2
- 0111 = 4 ~ ∞
以降は、0 ~ 0.25 と 4 ~ ∞ の区間に絞って説明する。
- 00000 = 0
- 00001 = 0.0625 (1/16)
- 00010 = 0.25 (1/4)
- 01110 = 4
- 01111 = 16 ~ ∞
ここで、4 = 221、16 = 222 である。このように 0 や ±∞ を含む区間は「二重指数分割」する。
- 000000 = 0
- 000001 = 0.00390625 (1/256)
- 000010 = 0.0625 (1/16)
- 000011 = 0.125 (1/8)
- 000100 = 0.25 (1/4)
- 011100 = 4
- 011101 = 8
- 011110 = 16
- 011111 = 256 ~ ∞
このように、区間の両端の比が2より大きい場合は、「等比分割」する。 以上のような操作の結果として、表現が自然に自分の長さを含むような指数部と、残りの仮数部から成る、と見ることができるような表現が得られる。
利点として、単精度と倍精度、さらには4倍精度との相互変換が、この方式では単に右にビットを伸ばしたり切り落としたりするだけで良い、という点が挙げられる。また、1の近くでは桁数のほとんどが仮数部となるので精度が高い。
欠点としては、精度が変化するため従来の精度一定を前提としたノウハウに修正が必要かもしれない、-∞を除くワードのあらゆるビット表現に浮動小数点数としての意味が与えられるため、例外的な値を表現する方法を別に考えなければいけない、などといった点がある。浜田は1000...を符号なしの∞(射影モード[8]用。符号なしの0と対応する)とし、表現可能な最大と最小の絶対値を持つ値を、具体的にその値を表すのではなく±∞と±0を表現するものとする(0は、通常の0を符号なしの0とし、符号付きの+0や-0は、無限大で割った結果など例外的な値としてのみ現れる)、という方法を提案している。
この表現法の初出は1981年だが[9]、1983年に改良版が提案されている[10]のでそちらをまずは参照すべきである。[11]
エラー(誤差)
- オーバーフロー/アンダーフロー
- 演算結果が指数部で表現できる範囲を超える場合があるが、最大値を超えた場合はオーバーフロー、絶対値の最小より小さい場合はアンダーフローという。IEEE 754の場合、アンダーフローは、まず結果が非正規化数となり精度が低下し、さらに進むと結果が0になる。
- 桁落ち
- 絶対値がほぼ等しい異符号の数値同士の加算後や、同符号でほぼ等しい数値同士の減算の後、正規化で有効数字が減少すること。詳細は桁落ちを参照。
- 情報落ち
- 浮動小数点数値を加減算するときはまず指数を揃えなければならない。絶対値の非常に小さな値と絶対値の非常に大きな値との浮動小数点数の加減算を行うときは、まず指数を絶対値の大きい方に揃える桁合わせを行ない、それから加減算を行なう。そのため絶対値の小さな値は仮数部が右側に多くシフトされて下位の桁の部分が反映されずに結果の値が丸められて情報が欠落する。情報欠落ともいう。詳細は情報落ちを参照。
- 積み残し
- 情報落ちが繰り返し起こる場合を言う。たとえば [math]\sum_{n=0}^{100} \frac{1}{1.5^n}[/math] を n=0 の初項からn=100に向かって順番に加えて計算しようとすると、ある項から先で情報落ちが起こり、それ以降の項は無視されてしまうことになる。これを積み残しと呼ぶ。値の小さい項から大きい項に向かって加算をする(この例では逆順に加算をする)ことで対処できる場合もある(必ずしもそうすれば全て完全にうまくいくとは限らない)。対処としては、有理数演算などによって無誤差の計算を行うか、カハンのsummationアルゴリズムなどいくつかの効率的な手法が提案されている。
- 丸め誤差
- 仮数部の桁数が有限であるため、収まらない部分の最上位桁で四捨五入(2進法では0捨1入)して仮数部の桁数に丸めることによる誤差。
ディジタル信号処理
32bit-floatの場合には156[dB]、64bit-floatの場合には331[dB]もの広いダイナミックレンジを確保できる。 この広いダイナミックレンジで計算を行うことで、整数型のデータに変換して信号を出力する際に内部計算において累積した誤差を切り捨てることにより、出力データの精度の範囲内においては内部計算の誤差が現れないように処理を行うことが可能となる。
製品に収録する音声信号フォーマットに直す直前まで波形がクリップせず音声加工処理を行えるメリットが有るため、2000年代以降はDTMやDAWにおいては全ての処理工程で浮動小数点数を用いている。
従来よりDSPや音楽用ワークステーション等では、精度と計算コストの兼ね合いから32bit-floatが内部計算において標準的に用いられてきたが、2010年代以降はコンピュータの高性能化と低価格化を受けて、より高精度な64bit-floatで内部計算を行う場合が増えて来ている。
浮動小数点数を表現するための仮数部の桁数の関係で、32bit-integerよりも32bit-floatの方が量子化ノイズが大きい。従って、最終的に32bit-integerのデータを作成する場合には、内部計算においては64bit-float以上の精度を持つ浮動小数点数を用いるべきである。
脚注
- ↑ System/360のちょうど30年後である。
- ↑ パターソン&ヘネシー『コンピュータの構成と設計 第3版 別冊 歴史展望』第3章 pp. 53-55
- ↑ 『ハッカーのたのしみ』15章3節(pp. 283-285)
- ↑ 松井正一, 伊理正夫「あふれのない浮動小数点表示方式」情報処理学会論文誌 Vol. 21 No. 4(1980 Jul)pp. 306~313 NAID 110002723544
- ↑ 共立『アルゴリズム辞典』p. 677
- ↑ Data Length Independent Real Number Representation Based on Double Exponential Cut
- ↑ 「URR」という名前の初出は1984年1月の第25回プログラミング・シンポジウムにおける発表「(25-9) 新しい数値表現法URR」だと思われる
- ↑ 射影モード = projective mode、射影幾何における無限遠点のような、符号の付かない1点のみの無限大の値が実数に加わった(射影拡張実数)モード、拡大実数を参照。IEEE 754の検討段階では議論されたが、最終的な標準ではオミットされアフィンモードのみになった。
- ↑ 浜田穂積「二重指数分割に基づくデータ長独立実数値表現法」情報処理学会論文誌 Vol. 22 No. 6 (1981 Nov) pp. 521~526 NAID 110002723634
- ↑ 浜田穂積「二重指数分割に基づくデータ長独立実数値表現法 II」情報処理学会論文誌 Vol. 24 No. 2 (1983 Mar) pp. 149~156 NAID 110002723753
- ↑ 他に鎌田誠による解説や、共立『アルゴリズム辞典』p. 677 なども参考のこと。
- ↑ http://ci.nii.ac.jp/naid/110002724403 http://ci.nii.ac.jp/naid/40015918740 など
- ↑ http://dx.doi.org/10.1109/12.156546 http://ci.nii.ac.jp/naid/110002885170 http://ci.nii.ac.jp/naid/110002932278 http://ci.nii.ac.jp/naid/80003909822 http://ci.nii.ac.jp/naid/110002932023 http://ci.nii.ac.jp/naid/110002722057 など
参考文献
- IEEE 754 http://grouper.ieee.org/groups/754/
- "IEEE Standard for Binary Floating-Point Arithmetic", IEEE, ISBN 978-9996639524, (1985).
- Peter J. L. Wallis (Editor): "Improving Floating-Point Programming", Wiley, ISBN 978-0471924371,(1990).
- Michael L. Overton:"Numerical Computing With IEEE Floating Point Arithmetic", SIAM, ISBN 978-0898714821, (2001).
- Jean-Michel Muller:"Elementary Functions: Algorithms and Implementation", 2nd ed., Birkhaeuser, ISBN 978-0817643720, (2005).
- Jean-Michel Muller:"Handbook of Floating-Point Arithmetic", Birkhaeuser, ISBN 978-0817647049, (2009).
- Peter Kornerup, David W. Matula: "Finite Precision Number Systems and Arithmetic", Cambridge University Press, ISBN 978-0521761352, (2010).
関連項目
外部リンク
- 浮動小数点演算について (1991 年 3 月発行の "Computing Surveys" に掲載された "Every Computer Scientist Should Know About Floating-Point Arithmetic" 稿 (David Goldberg著) を再編集したもの)