浮動小数点数

**浮動小数点数**（ふどうしょうすうてんすう、英: floating-point number）は、実数をコンピュータで処理（演算や記憶、通信）するために有限桁の小数で近似値として扱う方式であり、人間が多く用いる10進数での数値の計算や表記に加えて、コンピュータの数値表現で多く用いる2進数の数値でも採用されている。多くの場合、符号部、固定長の指数部、固定長の仮数部、の3つの部分を組み合わせて、数値を表現する。

## 概要
この節はパターソンらの記述に基づく。

実数は0以上かつ1以下のような有限の範囲でも、無限個の値（種類）が存在するため、コンピュータでは妥当なビット数で有限個の値（種類）の近似値で扱う必要がある。

実数-1/3は10進数表現では無限小数となるが、有限桁の小数で近似値を表記できる。下の例では10進数での4桁としている。
: -1/3
: -1 x 0.33333333333333...
: -1 x 0.3333 x 100
: -1 x 3.333  x 10-1
下の2つの表記は科学記数法 (scientific notation) とよばれ、小数点より左側の整数部分を1桁とする。
科学記数法のうち、仮数部の最上位の桁が0以外（10進表記では1から9）であるものを、正規化数 (normalized number) とよび、
上記の最後の表示が該当する。科学記数法も、10進数表記での浮動小数点数である。

実数-1/3はまた、2進数でもその近似値を有限桁の小数で表記できる。下の例では2進数17桁としている。
: -1/3
: -1 x 0.01010101010101010101010101010101...
: -1 x 0.0101010101010101
: -1 x (2-2 + 2-4 + 2-6 + 2-8 + 2-10 + 2-12 + 2-14 + 2-16)
: -1 x (1/4 + 1/16 + 1/64 + 1/256 + 1/1024 + 1/4096 + 1/16384 + 1/65536)
: -0.333328247（近似値の10進数表記）

2進数の小数も科学記数法で表記できる。
: -1 x 0.0101010101010101 x 20
: -1 x 0.101010101010101 x 2-1
: -1 x 1.01010101010101 x 2-2
上記は同じ値を、小数点の位置を移動し異なる表記にしているため、2進数表記での浮動小数点と呼ばれる。一番下の表記は、正規化数である。

コンピュータ内部での演算処理に最も適した浮動小数点数の表現は基数2であり、符号 (sign) S、仮数 (significand) F、指数 (exponent) Eにより下記の式で表記できる。
: (-1)S x F x 2E
数値に対する演算をあまり行なわずに数値を格納したり比較をする場合，あるいは演算が10進数でなければ正しく表せないような（お金の計算などの）用途では，計算機内部で10進数表現が
用いられる場合がある。

## 浮動小数点数のフォーマット
浮動小数点数のフォーマットには、以下で説明するものの他、以前は多数あった。

* 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 形式で表現する値は

: 半精度の場合： (&minus;1)符号部 × 2指数部 &minus; 15 ×（1 + 仮数部）
: 単精度の場合： (&minus;1)符号部 × 2指数部 &minus; 127 ×（1 + 仮数部）
: 倍精度の場合： (&minus;1)符号部 × 2指数部 &minus; 1023 ×（1 + 仮数部）
: 四倍精度の場合： (&minus;1)符号部 × 2指数部 &minus; 16383 ×（1 + 仮数部）

である。

ただし、IEEE 754 形式の指数部は複雑で、以下のような役割も持つ。

* 通常の浮動小数点数（正規化数）を表現するのは、指数部が単精度で 254 ～ 1（127 ～ &minus;126）、倍精度で 2046 ～ 1（1023 ～ &minus;1022）の範囲のときである
* 指数部が、単精度の場合 255（128）、倍精度の場合 2047（1024）のとき：
*: 仮数部が 0 以外の場合は、非数（NaN; Not a Number）を表す
*: 仮数部が 0 の場合は、符号部が 0 のときは正の無限大、符号部が 1 のときは負の無限大を表す
* 指数部が 0（単精度の場合 &minus;127、倍精度の場合 &minus;1023）のとき：
*: 非正規化数
* 指数部、仮数部ともに 0 のときは ±0 を表す

0 を 0 で割ろうとすると NaN になる。また、\sqrt{-1} も、求めるとNaNになる。

#### IEEE 754 で表現するまでの過程
2.5を例にとると、

* 仮数の符号は、+
* 仮数の絶対値は、2.5
* IEEE 754の基数は、2で固定（簡単のため、以下では省略）
* 指数は、0

であることから、まず次のように考える。

: (&minus;1)0 × 2.5 × 20

仮数部は1未満でなければならないため、仮数の値2.5を（この例では右へ）シフトし正規化する。基数は2、コンピュータの内部表現は2進法であるため、シフト量は1ビットである。さらに、右シフトしてになったことを相殺するため、指数に1を加える（もし左シフトなら、指数から1を引く）。
値をシフトすることで表現範囲を広げ、丸め誤差を少なくなるようにしている。この操作を正規化という。正規化は基数の±1乗を繰り返し求めればよい。

このままでは (&minus;1)0 × 1.25 × 21 となり、仮数の絶対値は1未満ではないが、仮数部は 仮数 &minus; 1 と決められているため、次のようになる。

: (&minus;1)**0** × (1 + **0.25**) × 21
* 符号部は、0
* 仮数部は、0.25
* 指数は、1

指数部は、指数に127をバイアスすることが決まっているため

: (&minus;1)**0** × (1 + **0.25**) × 2(**128** &minus; 127)
* 符号部は、0
* 仮数部は、0.25
* 指数部は、128

2進法では、

* 符号部（1ビット）：+ → 0
* 仮数部（23ビット）：0.25 → 
* 指数部（8ビット）：128 → 

浮動小数点は、最上位ビットから符号部、指数部、仮数部の順に符号化するため

: 2進値：、16進値：
:

#### bfloat16

IEEE 754 形式から派生した浮動小数点数の形式。符号部 1 ビット ・ 指数部 8 ビット ・ 仮数部 7 ビットである。

つまり、bfloat16 形式で表現する値は
: (&minus;1)符号部 × 2指数部 &minus; 127 ×（1 + 仮数部）
である。

採用事例
* インテル - Intel Xeon Cooper Lake マイクロアーキテクチャ以降、Nervana NNP-L1000 など
* ARMアーキテクチャ - Armv8.6-A
* Google - Tensor Processing Unit 2.0 以降
* NVIDIA - Ampere マイクロアーキテクチャ以降
* AMD - Instinct
* Amazon.com - AWS Inferentia、Amazon Elastic Inference など

#### FP8
IEEE 754 形式から派生した浮動小数点数の形式。以下の2種類がある。E4M3は無限大を表現できない。2023年にOpen Compute Projectで仕様が制定されたが、IEEEがWorking Group P3109にてそれらの結論とは異なる仕様を検討中である。
* E4M3 - 符号部 1 ビット ・ 指数部 4 ビット ・ 仮数部 3 ビット
* E5M2 - 符号部 1 ビット ・ 指数部 5 ビット ・ 仮数部 2 ビット

採用事例
* インテル - Gaudi 2以降
* NVIDIA - Hopper マイクロアーキテクチャ以降
* AMD - Instinct MI300以降, Versal AI Edge Series Gen 2 など

その他の独自規格としては、2019年のIBMのhybrid FP8や、2021年のTeslaのconfigurable FP8、2022年のGraphcoreのFP8
がある。AMD, Arm, Google, Intel, Meta, NVIDIAがOpen Compute Projectで合意するまでは仕様が分裂気味だったが、一応の決着を見た所、IEEEのWorking Group P3109がE4M3で無限大を表現できるように異なる仕様を検討している。

#### FP6
IEEE 754 形式から派生した浮動小数点数の形式。以下の2種類がある。無限大とNaNは表現できない。
* E2M3 - 符号部 1 ビット ・ 指数部 2 ビット ・ 仮数部 3 ビット
* E3M2 - 符号部 1 ビット ・ 指数部 3 ビット ・ 仮数部 2 ビット

採用事例
* NVIDIA - Blackwell マイクロアーキテクチャ以降

#### FP4
IEEE 754 形式から派生した浮動小数点数の形式。無限大とNaNは表現できない。
* E2M1 - 符号部 1 ビット ・ 指数部 2 ビット ・ 仮数部 1 ビット

採用事例
* NVIDIA - Blackwell マイクロアーキテクチャ以降。FP6、FP4もNvidia社はGPU製品Blackwell（2024年3月発表）でAI用を想定して導入した。

### IBM方式

IBM方式は、IBM社がSystem/360で導入し、以後同社の標準としてSystem/370などのメインフレームで使った方式である（System/390では、従来形式のサポートは残すもののIEEE 754を使用するよう改めた）。指数部が2の冪ではなく16の冪を表すという特徴がある。この方式は、より大きな範囲を少ないビット数の指数部で表すことができ、そのぶんのビットを仮数部の桁数に使うことで精度も確保できるように一見思える。しかし、仮数部にケチ表現を使うことができず、さらに指数部の変化の前後で、仮数部のLSBが表現する値の刻み幅が16倍変化するため、2べきの場合に比べて最悪の場合には2進で3ビット分の精度が損なわれるため、一般には大成功であったと評されたSystem/360の設計において良くなかった点の一つとして挙げられる。（浮動小数点数の加減算の際に必要となる仮数部のシフトが4ビット単位となるのでシフト回数が減ることで演算が程度高速になる利点も16進数が採用された理由であった。）

特に単精度において、前世代機のIBM 7094（全部で36ビット）よりも桁数を減らした（32ビット）ことと相まって精度が大きく損なわれた。その他にも問題があり、ユーザグループであるSHAREから改善提案が出され、その多くを受け入れて多大なコストのかかる改修をおこなったほどであり、これを記憶しているIBMの古参社員は「身の縮む思い」をおぼえているという。

また、計算対象の数値がベンフォードの法則に従って分布していた場合、計算対象として精度の低い数（仮数部の最上位4ビットが0b0001）の現れる確率は1/15にはならず、もっと高い。

IBM方式の単精度浮動小数点数では、符号部1ビット、指数部7ビット、仮数部24ビットで表現されている。各部は次のように定義されている。

* 符号部は、0を正、1を負とする
* 仮数部は、1未満の16進小数とする
* 指数部は、16を基数とした指数に64をバイアスした値で表す

符号部は仮数の符号を表す。
指数部は&minus;1663～&minus;16&minus;64と16&minus;64～1663の範囲が表現できる。

#### IBM方式で表現するまでの過程
1.5を単精度のIBM方式で表現するには、次のようになる。

:(&minus;1)0 × 1.5 × 160

仮数部は1未満でなければならないため、値を（この例では右へ）シフトする。ただし、基数が16で、コンピュータの内部表現は2進法であるため、シフト量は4ビットである（24 = 16）。加えて正規化し、その結果は次の通り。

:(&minus;1)0 × 0.09375 × 161

次に指数部を、64をバイアスしたゲタ履き表現（エクセス64）で表現する。バイアスにより、0～127のビットパターンで、整数値&minus;64～+63を表現するということになる（&minus;64 + 64 = 0、63 + 64 = 127）。
よって、今回の例では以下のようになる。

:(&minus;1)**0** × **0.09375** × 16(**65** &minus; 64)

2進法では、

* 符号部（1ビット）：+ → 0
* 仮数部（24ビット）：0.09375 → 000110000000000000000000
* 指数部（7ビット）：65 → 1000001

浮動小数点は、最上位ビットから符号部、指数部、仮数部の順に符号化するため

: 2進値：0 1000001 000110000000000000000000、16進値：

### 指数部と仮数部を可変とする方式
任意精度演算と、従来の指数部と仮数部を共に固定長とする形式の中庸と言えるような方式が、いくつか提案されている。絶対値が1に近い値では指数部の桁数を短くし、仮数部の桁数を多くとって、よく使われる値を精度よく表現する。絶対値が極端に大きい値や小さい値には、精度とひきかえに指数部の桁数を増やすことで対応する。以下で述べる方式を提案している文献では、アプリケーションとして、通常の浮動小数点計算には、指数が大きくなり過ぎることがあって向かないとされている:en:Graeffe's methodをうまく扱えたという例が示されている。欠点としては、精度が変化するため従来の精度一定を前提としたノウハウに修正が必要かもしれない。

#### 松井・伊理の表現法
松井正一と伊理正夫が提案した方式で、符号と絶対値による表現法である。論文中に示された例では、64ビットの倍精度浮動小数点数として、仮数部の長さnを示す情報6ビットと、（符号部を含む）mビットの指数部とnビットの仮数部（m+n = 58）からなる。彼らは、オーバーフローを起こさせないための、より大きい数やより小さい数の表現や、無限大などの例外的な値を含めた算術（IEEE標準の±∞や&minus;0の扱いに似ているが、より拡張されている）も提案している。

#### 浜田のURR
浜田穂積が提案した方式で、Universal Representation of Real numbersの意でURRと名付けられている。&minus;∞ ～ 0 ～ ∞ の区間を、次のように分割しながら、二進法による表現に対応付ける、というのが基本的な考え方で、「符号と絶対値」形ではなく、浮動小数点の表現としては比較的珍しい2の補数の形をしている。
* 100 = &minus;∞
* 101 = &minus;2
* 110 = &minus;1
* 111 = &minus;0.5
* 000 = 0
* 001 = 0.5
* 010 = 1
* 011 = 2 ～ ∞
ここで±1の前後は、区間の両端の比が2なので、指数部の表現は終わったとみなすことができ、残りの桁は仮数部のように扱う（±1の前後は、以後は1/2で等差分割する）。次のように分割を続ける。
* 1000 = &minus;∞
* 1001 = &minus;4
* 1010 = &minus;2
* 1011 = &minus;1.5
* 1100 = &minus;1
* 1101 = &minus;0.75
* 1110 = &minus;0.5
* 1111 = &minus;0.25
* 0000 = 0
* 0001 = 0.25
* 0010 = 0.5
* 0011 = 0.75
* 0100 = 1
* 0101 = 1.5
* 0110 = 2
* 0111 = 4 ～ ∞
以降は、符号ビットが0である0 ～ 0.5 と 2 ～ ∞ の区間に絞って説明する。
* 0 00000 = 0
* 0 00001 = 0.00390625 (1/256)
* 0 00010 = 0.0625 (1/16)
* 0 00100 = 0.25 (1/4)
* 0 01000 = 0.5 (1/2)
* 0 11000 = 2
* 0 11100 = 4
* 0 11110 = 16
* 0 11111 = 256 ～ ∞
ここで、2 = 220、4 = 221、16 = 222、256 = 223 である。このように 0 や ±∞ を含む区間は「二重指数分割」する。
* 0 000000 = 0
* 0 000001 = 0.0000152587890625 (1/65536)
* 0 000010 = 0.00390625 (1/256)
* 0 000011 = 0.015625 (1/64)
* 0 000100 = 0.0625 (1/16)
* 0 000110 = 0.125 (1/8)
* 0 001000 = 0.25 (1/4)
* 0 111000 = 4 (22)
* 0 111010 = 8 (23,3=(2+4)/2)
* 0 111100 = 16 (24)
* 0 111101 = 64 (26,6=(4+8)/2)
* 0 111110 = 256 (28)
* 0 111111 = 65536 ～ ∞
このように、区間の両端の比が2より大きい場合は、「等比分割」する。

以上のような操作の結果として、指数部が0以上の場合は
* "0 10" = 0
* "0 11(1がn個)0(n個のビット列Bn)" = 1Bn (ガンマ符号の桁数出力とその後の"1"をビット反転したもの)
指数部が0未満の場合は
* "0 01" = 上述の"0 10"の符号ビット以外をビット反転させたもの = 2進数"0"をビット反転させたもの = &minus;1
* "0 00(0がn個)1(n個のビット列Bnをビット反転させたもの)" = 上述の"0 11(1がn個)0(n個のビット列Bn)"の符号ビット以外をビット反転させたもの = 2進数"1Bn"をビット反転させたもの = &minus;(1Bn)&minus;1
ビット反転して0以上にした後に上述の方法を適用した指数部を、再びビット反転したものとなる。
こうして、負数に拡張されたガンマ符号によって自分の長さを含む指数部と、残りの仮数部から成る、と見ることができるような表現が得られる。

利点として、ビット表現を2の補数と解釈しても値・絶対値の大小関係が一致しているため、
* 単精度と倍精度、さらには4倍精度や、一部ビットをデータ型判別などの別用途に転用している処理系で用いられる7bitや30bitなど、任意のビット長表現との相互変換・丸め操作が、この方式では単に最下位ビットを追加したり切り捨てるだけで良い
* 大小関係の比較演算や符号反転に必要な、回路や計算アルゴリズムが、整数でのそれと同一
という点が挙げられる。

表現形式の取り決め事項が、最下位ビットの追加・切り捨てだけで任意に変換でき、精度の問題に過ぎない、ビット長のみである。また、2の補数の形を採るという考え方が提案当初は独創的であった。このため、異なる処理系との間のデータ交換を容易にする普遍性(「URR」のUはUniversal「普遍性」の頭文字)を当方式は備えていた。しかし、指数部に使われる整数の符号化にはガンマ符号以外にも様々な手法が使えるため、後に、互換性の無い様々な亜種の出現を許した。

欠点としては、&minus;∞を除くワードのあらゆるビット表現に浮動小数点数としての意味が与えられるため、例外的な値を表現する方法を別に考えなければいけない、などといった点がある。浜田は1000...を符号なしの∞（射影モード用。符号なしの0と対応する）とし、表現可能な最大と最小の絶対値を持つ値を、具体的にその値を表すのではなく±∞と±0を表現するものとする（0は、通常の0を符号なしの0とし、符号付きの+0や&minus;0は、無限大で割った結果など例外的な値としてのみ現れる）、という方法を提案している。

この表現法の初出は1981年だが、1983年に改良版が提案されているのでそちらをまずは参照すべきである。

いくつかの実装の報告や改良の提案などがある。

##### GustafsonのPosit
この方法は浜田方式のリバイバルのようなものである。
浜田方式との違いは、指数部の表現方法である。浜田方式は(整数として解釈した時の大小関係を保つように修正を加えた)ガンマ符号を用いるのに対し、当方式は指数部を上位ビットと固定長の下位ビットに分け、上位ビットは(浜田方式と同様の修正を加えた)アルファ符号で表現する。このため、絶対値が1付近では、下位ビットに固定長のビットを要する当方式より浜田方式の方が仮数部ビットを多くとれて精度が高くなるが、そこから少し離れると当方式の方が精度が良くなり、更に離れると浜田方式の方が良くなる。
*John L. Gustafson and Isaac Yonemoto: "Beating Floating Point at its Own Game: Posit Arithmetic", DOI:10.14529/jsﬁ170206
*「ISC 2019 - ディープラーニングに最適な数値表現のPosit」（マイナビニュース記事、2019年7月23日）

## エラー（誤差）

; オーバーフロー／アンダーフロー
: 演算結果が指数部で表現できる範囲を超える場合があるが、最大値を超えた場合は**オーバーフロー**、絶対値の最小より小さい場合は**アンダーフロー**という。IEEE 754の場合、アンダーフローは、まず結果が非正規化数となり精度が低下し、さらに進むと結果が0になる。
; 桁落ち
: 絶対値がほぼ等しい異符号の数値同士の加算後や、同符号でほぼ等しい数値同士の減算の後、正規化で有効数字が減少すること。詳細は桁落ちを参照。
; 情報落ち
: 浮動小数点数値を加減算するときはまず指数を揃えなければならない。絶対値の非常に小さな値と絶対値の非常に大きな値との浮動小数点数の加減算を行うときは、まず指数を絶対値の大きい方に揃える桁合わせを行ない、それから加減算を行なう。そのため絶対値の小さな値は仮数部が右側に多くシフトされて下位の桁の部分が反映されずに結果の値が丸められて情報が欠落する。情報欠落ともいう。詳細は情報落ちを参照。
; 積み残し
: 情報落ちが繰り返し起こる場合を言う。たとえば \sum_{n=0}^{100} \frac{1}{1.5^n} を n=0 の初項からn=100に向かって順番に加えて計算しようとすると、ある項から先で情報落ちが起こり、それ以降の項は無視されてしまうことになる。これを積み残しと呼ぶ。値の小さい項から大きい項に向かって加算をする（この例では逆順に加算をする）ことで対処できる場合もある（必ずしもそうすれば全て完全にうまくいくとは限らない）。対処としては、有理数演算などによって無誤差の計算を行うか、カハンのsummationアルゴリズムなどいくつかの効率的な手法が提案されている。
; 丸め誤差
: 仮数部の桁数が有限であるため、収まらない部分の最上位桁で四捨五入（2進法では0捨1入）して仮数部の桁数に丸めることによる誤差。

## 脚注
### 注釈

### 出典

## 参考文献
* 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).

## 関連項目

* コンピュータの数値表現
* 固定小数点数
* 単精度浮動小数点数
* 誤差、端数処理
* エクセス3
* 二進化十進表現
* 精度保証付き数値計算
* ハイレゾリューションオーディオ

## 外部リンク
*浮動小数点演算について （1991 年 3 月発行の "Computing Surveys" に掲載された "Every Computer Scientist Should Know About Floating-Point Arithmetic" 稿 (David Goldberg著) を再編集したもの）