數值穩定與誤差

作成者:カランカラン
💡

質問やフィードバックがありましたら、フォームからお願いします

本文は台湾華語で、ChatGPT で翻訳している記事なので、不確かな部分や間違いがあるかもしれません。ご了承ください

数値の安定性と誤差

(0.1 + 0.2) == 0.3 という一見すると当然の等式ですが、コンピュータが浮動小数点数を保存する方法のため、多くのプログラミング言語ではこの等式が成り立たず、結果は false となります。

しかし、別の問題として、なぜ (0.5 + 0.25) == 0.75 という等式は成立するのでしょうか?

浮動小数点数の演算を行うと、必ず誤差が発生します。次に、なぜ誤差が生じるのか、そして計算上どのようにそれを避けることができるかを考察します。

コンピュータにおける浮動小数点数の保存方法

浮動小数点数はコンピュータ内でビットの配列として表され、IEEE754によって規定されています。単精度浮動小数点数は32ビット、倍精度は64ビットで、正負を示す符号ビット、小数部、指数部に分かれています。

  • 符号ビット(1ビット):0は正数、1は負数
  • 小数部
  • 指数部
型別大きさ指数部小数部
単精度32ビット8ビット23ビット
倍精度64ビット11ビット52ビット

単精度の場合、指数部は8ビットで、表現できる範囲は0から255ですが、負数を表現するために、IEEE754の規定によりオフセットを加える必要があります。単精度の場合、このオフセットは127です。

例として、-14.75の浮動小数点数表現を見てみましょう:

  • 符号ビット:負数なので 1
  • 指数部:14.75を二進数で表すと 1110.11 となり、正規化後は 1.11011 * 2^3 です。指数部は3に127を加えて130となり、二進数で 10000010 になります。
  • 小数部:11011、残りのビットは 0

したがって、-14.75の浮動小数点数表現は:1 10000010 11011000000000000000000 です。000022

ここから、誤差がどこから来るのかもわかります。指数が負数になると、得られる数値はすべて 0 < x < 1 の範囲に収束します。そのため、2^-x で表せない数値は、できるだけ近づけることしかできず、完全には一致しません。初めに述べた 0.5 + 0.25 は、これらの数値が 2^-1 + 2^-2 として表現できるため、計算上誤差が生じることはありません。

なぜこのように保存するのか?

科学的記数法を使用すると、さまざまなスケールの数値を扱いやすく、一定の精度を保つことができます。例えば、0.000000123451234567890000 は、科学的記数法によってそれぞれ 1.2345E-71.23456789E12 と表現できます。コンピュータでは通常、浮動小数点数形式で保存されており、科学的記数法に似ていますが、十進数を二進数に変換したものです。

実数は無限に存在しますが、コンピュータの保存空間は限られているため、どのように保存しても必ず誤差が生じます。私たちができるのは、精度と表現可能な数値の範囲とのトレードオフを行うことだけです。

有効数字

有効数字は、私たちが精度を判断するための指標です。例えば、0.0010.0135 という数値は、1×1031 \times 10^{-3}1.35×1021.35 \times 10^{-2} と書くことができます。この場合、0.001 の有効数字は1桁、1.35 の有効数字は3桁です。有効数字の桁数が多いほど、精度は高くなります。

ウィキペディアには簡単な判断ルールがあります:

  • すべての非ゼロ数字は有効です
  • 非ゼロ数字間のゼロも有効です
  • 前置ゼロは常に無効です
  • 小数点を必要とする数に対して、後置ゼロ(最後の非ゼロ数字の後のゼロ)は有効です
  • 小数点を必要としない数に対して、後置ゼロは有効である場合もあれば無効である場合もあります。追加の記号や誤差情報に基づいて判断する必要があります。

有効数字の消失

絶対値が非常に近い二つの浮動小数点数で減算を行うと、大部分の数字が同じため、残るのはたくさんの0となり、有効数字が減少します。この現象は「有効数字の消失」と呼ばれます。

例として、(1.234567890 - 1.234567889) を考えます。結果は 0.000000001 ですが、精度が不足している場合、これは 0 になる可能性があります。

これは数値計算において特に注意が必要です。例えば、倍角と半角の公式:

sin2(θ2)=1cosθ2\sin^2(\frac{\theta}{2}) = \frac{1-\cos\theta}{2}

角度が比較的低い場合、cosが1に非常に近いため、1から引くと有効数字が失われやすいです。例えば、角度が1度のとき、倍角公式を使用すると(有効数字が6桁の場合):

1cos1°2=10.9998472=0.0000765=7.65×105\frac{1-\cos1\degree}{2} = \frac{1 - 0.999847}{2} = 0.0000765 = 7.65 \times 10^{-5}

右側の公式を使って直接表を参照すると:

sin2(1°2)=0.008726532=0.00007615232=7.61523×105\sin^2(\frac{1\degree}{2}) = 0.00872653^{2} = 0.00007615232 = 7.61523 \times 10^{-5}

二つの誤差がかなり明確であることがわかります。数値計算では特に注意が必要です。有効数字の消失を避けるためには、以下の方法があります:

  • 絶対値が近い二つの数での演算をできるだけ避ける

  • 他の公式を使って計算する(例えば、上記の倍角公式)

    • これは実際には、絶対値が近い二つの数での演算を避けることになります。
  • 精度を高める

結論

比較的経験のあるエンジニアは、浮動小数点数演算に誤差が生じることをある程度理解しており、0.1 + 0.2 != 0.3 の理由も知っています。この文書では、小数の保存方法、IEEE754、そして有効数字の消失について深く考察しました。

倍角公式は高校の三角関数でよく出てくる問題で、私にとっては単なる公式の適用に過ぎません。

しかし、実際のアプリケーションはコンピュータを介して計算されており、現実の生活では30度や60度のように計算しやすい数字ばかりではありません。教師も有効数字の問題については触れないでしょう。

この記事が役に立ったと思ったら、下のリンクからコーヒーを奢ってくれると嬉しいです ☕ 私の普通の一日が輝かしいものになります ✨

Buy me a coffee