14.2.3. 精度と誤差
浮動小数点表現で表せる数の精度や、特別な値の表現を調べましょう。
精度と範囲 #
64bit のIEEE754 浮動小数点表現は \(\langle s,m,e \rangle\) を使うものでした。
\[x \approx ({-1})^s \underbrace{(1+m \cdot 2^{-52})}_{\text{仮数}} \cdot 2^{\overbrace{(e-1023)}^{\text{指数}}}\]符号部 \(s\) | 指数部 \(e\) | 仮数部 \(m\) | |
---|---|---|---|
符号長 | 1 ビット | 11 ビット | 52 ビット |
精度は仮数部で決まり 53 ビット、10 進数の 16 桁程度になります。
表現できる絶対値の最大最小値は、指数部が重要です。 指数部 \(e\) の最小値 \(0\) と最大値 \(2^{11}-1\) (全ビット1)は、0 など特殊な値を表現するために予約されています (仮数 \((1+m \cdot 2^{-52})\) は0を表せません)。そのため \(e \in [1,2^{11}-2]\) , \(2^{e-1023}\in[2^{-1022},2^{1023}]\) です。 表そうとした数の 絶対値 が表現範囲の最大値を超えることをオーバーフロー (overflow) と呼び、最小値を下回ることを アンダーフロー (underflow) と呼びます。 オーバーフロー限界は \(2^{1024} \approx 1.8\cdot 10^{308}\) 、アンダーフロー限界は \(2^{-1022} \approx 2.2\cdot 10^{-308}\) になります。
これらの通常の数を、 (あとの非正規化数との対比で) 正規化数 と呼びます。
特別な値 #
指数部 \(e\) の最小値 \(0\) と最大値 \(2^{11}-1\) (全ビット1)は、以下の特別な数を表現します。
種類 | Exp(指数部) | Fraction(仮数部) |
---|---|---|
ゼロ | 0 | 0 |
非正規化数 | 0 | 0以外 |
無限大 | 2047 | 0 |
NaN | 2047 | 0以外の任意 |
実用上は、 0 以外が表れないように計算を進める方が無難です。
- ゼロ
- 指数部のビットが全て 0 で、仮数部のビットも全て 0 のものとして表現されます。 符号部によって 0 (+0) と −0 の区別があります。 たとえば \(1/0=+\infty\) , \(1/(-0)=-\infty\) と差が生じます。
- 非正規化数
- 指数部のビットが全て 0 (つまり \(e=0\) )で、仮数部が 0 以外のものを非正規化数といい、通常の正規化数と 0 の間を表現する数となります。 \[x = ({-1})^s ( m \cdot 2^{-52}) \cdot 2^{-1022}\] 非正規化数の絶対値の最小は \(m=1\) のときで \(2^{-52} \cdot 2^{-1022} \approx 10^{-323}\) となります。非正規化数は計算が遅くなるリスクがあります。
- 無限大
- 指数部のビットが全て 1 で、仮数部のビットが全て 0 は無限大です。符号部によって、正負の区別があります。 \(\pm\infty\) に 0 でない有限の数を足しても結果は変わりません。 \(\pm\infty \cdot 0\) や \(\infty + (−\infty)\) は次に説明する非数 (NaN) となります。
- 非数 (NaN)
- 指数部のビットが全て 1 で、仮数部のビットのどこかが 1 になっているものは非数 (NaN, Not a Number) です。 NaN は、0 / 0 や log(-1) などで発生します。
誤差の拡大 #
有限bit数での表現という制約から、ほとんどの場合に浮動小数点表現は 表現誤差 を伴うことを前ページで紹介しました。 表現誤差自身はとても小さいものですが、この誤差は計算中にさらに拡大することがあります。いくつか例を紹介します。
- 桁落ち
- 絶対値の近い数の加減算で、上位の桁が0になり、有効数字が減少することです。 同じ \(e\) で \(m\) の上位ビットが揃った異なる数で発生します。10進でも生じます \[ \underbrace{1.231}_{{\text{4桁}}}\underbrace{\text{\_\_\_}}_{\substack{\color{gray}\text{誤}\\\color{gray}\text{差}}} - \underbrace{1.230}_{{\text{4桁}}}\underbrace{\text{\_\_\_}}_{\substack{\color{gray}\text{誤}\\\color{gray}\text{差}}} = \underbrace{0.001}_{{\text{\color{red}{1桁!}}}}\underbrace{\text{\_\_\_}}_{\substack{\color{gray}\text{誤}\\\color{gray}\text{差}}} \] 有効数字が減少した後で、乗算で桁を大きくすると、誤差の絶対値が拡大します。
- 情報落ち
- 差の大きな数の加減算で小さな数が無視されることです。 2進 52 桁以上差がある数の加減算で顕著で、 \(2^{-53}\) 自体は正確に表現できるのに、 \(1 + 2^{-53} = 1\) となってしまいます。 情報落ち単独では有効数字を減らしませんが、その後に桁落ちが発生すると誤差が明確になります。
- 打ち切り誤差
- \(\sin, \exp\) などは本質的に近似計算しかできないために生じます。