数値計算において避けられない問題として、さまざまな種類の誤差があります。その中でも特に重要な「丸め誤差」と「打ち切り誤差」について解説します。これらは異なる原因と特性を持ちながらも、数値計算の精度に大きく影響する基本的な概念です。
1. 丸め誤差と打ち切り誤差
丸め誤差と打ち切り誤差は、数値計算における誤差の一種で、それぞれ異なる原因と特性を持っています。
1.1. 丸め誤差 (Rounding error)
丸め誤差 (Rounding error)は、数値を近似することによって生じる誤差です。例えば、無理数や循環小数を有限の桁数で表現するときに生じます。コンピュータは無限に続く小数を完全に表現することはできないため、一定の桁数で数値を「丸め」ます。これにより、実際の値と計算値との間に微小な差が生じ、これが丸め誤差です。例えば、πを3.14や3.14159などと近似するとき、丸め誤差が生じます。
丸め誤差の基本的な仕組み
コンピュータの数値表現の根本に関わる問題として、私たちが普段使用する10進数とコンピュータ内部の2進数表現の違いがあります。
例えば、10進数の0.1は2進数では次のように表現されます:
\(0.0001100110011001100110011\)…(無限に続く)
コンピュータはメモリが有限なので、この無限に続く数を完全に保存できません。そのため、ある桁で切り捨てる必要があります。この切り捨てによって生じる誤差が「丸め誤差」です。
丸め誤差の具体例
最も有名な例として、多くのプログラミング言語で次のような計算をすると意外な結果になります:
0.1 + 0.2 = 0.30000000000000004
期待値は0.3ですが、実際には微小な誤差が生じています。これは0.1と0.2がコンピュータ内部では正確に表現できないためです。
また、繰り返し計算でも丸め誤差は積み重なります:
0.1を10回足す ≠ 1.0
実際の計算結果は\(0.9999999999999999\)のようになり、厳密に1.0にはなりません。
丸め誤差を理解するための例え
10進数で説明すると、\(1/3 = 0.333333\)…と無限に続きます。これを小数点以下2桁で表すと\(0.33\)となり、厳密には\(1/3\)ではなくなります。コンピュータの中では、これと同じことが2進数で起きています。
浮動小数点数の仕組み
コンピュータは通常、「浮動小数点数」という形式で小数を扱います。これは科学的記数法に似ています:
\(1.23456 × 10^2 = 123.456\)(10進数の例)
コンピュータでは:
\(1.xxxxx × 2^y\)(2進数)
実際にはIEEE 754という規格に従い、次の3つの部分に分けて保存します:
- 符号部(正か負か)
- 指数部(2の何乗か)
- 仮数部(有効数字)
標準的な倍精度浮動小数点数(64ビット)では:
- 符号部: 1ビット
- 指数部: 11ビット
- 仮数部: 52ビット
この表現形式による限界が丸め誤差の根本的な原因です。
1.2. 打ち切り誤差 (Truncation error)
打ち切り誤差 (Truncation error)は、無限の計算を有限のステップで近似することによって生じる誤差です。例えば、テイラー級数を用いて関数を近似するとき、無限に続く項を有限個の項で打ち切ると、打ち切り誤差が生じます。また、微分や積分を離散化して近似する際にも打ち切り誤差が生じます。
打ち切り誤差の基本的な仕組み
打ち切り誤差は主に以下の場面で発生します:
- 無限級数を有限項で打ち切る場合
- 連続的な関数を離散化する場合
- 微分方程式を数値的に解く場合
打ち切り誤差の具体例
例えば、指数関数 e^x は次の無限級数で表されます:
\(e^x = 1 + x + x²/2! + x³/3! + x⁴/4! +\) …
実際の計算では、無限に続く項をどこかで「打ち切る」必要があります。例えば、e^1を計算する場合:
- 1項まで: \(1 + 1 = 2\)
- 2項まで: \(1 + 1 + 1/2 = 2.5\)
- 3項まで: \(1 + 1 + 1/2 + 1/6 ≈ 2.667\)
- …
- 10項まで:\( ≈ 2.7182818\)
- 真の値: \(e ≈ 2.7182818284590452\)…
項を増やすほど精度は上がりますが、どこかで打ち切る必要があります。この打ち切りによって生じる誤差が「打ち切り誤差」です。
また、微分の数値計算でも打ち切り誤差は生じます。微分の定義は極限を使って:
\(f'(x) = lim_{h\to0} \frac{f(x+h) – f(x)}{h}\)
しかし、コンピュータでは h を本当の0にはできないため、小さな値(例:\(0.0001\))で近似します。これによる誤差も打ち切り誤差の一種です。
2. 丸め誤差と打ち切り誤差の違いを考える
丸め誤差と打ち切り誤差は、どちらもある桁以下を切り捨てるという意味で同じに思えてしまいます。本質的な違いはどこにあるのでしょうか。
確かに、丸め誤差と打ち切り誤差はともに「ある桁以下を切り捨てる」という行為に関連していますが、その背景となる状況と目的が異なります。
2.1. 丸め誤差
これは主に「表現の制限」によって生じます。コンピュータは有限のビット数で数値を表現するため、それを超える精度の数値は適切に表現できません。そのため、特定の桁で数値を「丸め」ることになり、その結果として生じる誤差が丸め誤差です。丸め誤差は、数値そのものの表現に由来する誤差です。
2.2. 打ち切り誤差
これは「計算の近似」によって生じます。無限に続く計算を有限のステップで終了させるとき、あるいは連続的な現象を離散的に近似するときに生じます。例えば、テイラー級数のような無限級数を有限項で打ち切るときや、微分・積分を離散化するときなどに生じます。打ち切り誤差は、計算過程の近似に由来する誤差です。
両者の違いは、丸め誤差が「数値の表現」に関連し、打ち切り誤差が「計算の近似」に関連するという点にあります。それはすなわち、丸め誤差は計算機が表現できる数値の限界以下を処理することであり、打ち切り誤差は、計算機が表現できる範囲であるかどうかに関わらず計算過程を途中で終了することによる誤差ということです。
丸め誤差は、計算機が表現できる数値の精度(通常はビット数によって決まる)を超える数値を扱う際に生じます。これは、無理数や非常に大きなまたは小さな数値を表現する際に特に顕著になります。
打ち切り誤差は、計算過程を途中で終了することによって生じます。これは、無限に続く計算(例えば、級数や反復法)を有限のステップで打ち切るときや、連続的な現象を離散的に近似するとき(例えば、微分や積分の数値計算)に特に顕著になります。
これらの誤差は、数値計算の精度を決定する重要な要素であり、計算の設計やアルゴリズムの選択において考慮する必要があります。
3. さらに深く考える
打ち切り誤差の打ち切る計算の項数を増やしていくと丸め誤差の領域に入っていくことになるかと思います。そうするとそれ以上計算しても丸められてしまうということになり、仮に打ち切り誤差の項数をどんどん増やせば丸め誤差の範囲より大きい数値が得られるとしても事実上計算できないことになります。
打ち切り誤差を減らすために計算の項数を増やすと、その分だけ計算の精度が増すと考えられます。しかし、ある点を超えると、その計算結果は丸め誤差によって影響を受けるようになります。つまり、計算機が表現できる精度を超えた部分は丸められてしまいます。
具体的な例: 微分の数値計算
例えば、sin(x)の導関数をx=1の点で数値計算する場合、理論値はcos(1)≈0.5403ですが、前進差分法で計算すると:
- \(h=0.1: ≈0.4974\)(誤差大)
- \(h=0.001: ≈0.5399\)(誤差減少)
- \(h=0.000001: ≈0.5403\)(よい近似)
- \(h=0.0000000001\): 結果が不安定になる(丸め誤差の影響)
このように、hを小さくしていくと打ち切り誤差は減少しますが、ある点を超えると丸め誤差の影響が大きくなり、かえって全体の誤差が増加することがあります。
したがって、打ち切り誤差の項数をどんどん増やしても、ある程度以上になると丸め誤差によって結果が影響を受け、それ以上の精度向上は期待できないというのが一般的な理解です。
これは、数値計算における精度と効率のトレードオフの一例であり、適切なバランスを見つけることが重要です。
4. 実用的な対処法
4.1. 丸め誤差への対処
- 固定小数点演算: 整数に変換してから計算し、後で戻す方法
- 許容誤差(イプシロン): 完全な等価性ではなく、許容誤差内であれば「等しい」とみなす
- 専用ライブラリの使用: 高精度計算用のライブラリを使用する(例:decimal.js, big.js)
4.2. 打ち切り誤差への対処
- より高次の数値解法: 例えば、前進差分より中心差分、台形法よりシンプソン法
- 適応的ステップサイズ: 必要に応じて細かいステップを使用
- 誤差の推定と制御: 誤差が許容範囲内に収まるまで計算を続ける
5. まとめ
丸め誤差と打ち切り誤差は、数値計算において避けられない問題です。丸め誤差はコンピュータの数値表現の限界に由来し、打ち切り誤差は無限の計算過程を有限で近似することに由来します。
両者は異なる原因から生じますが、実際の数値計算では互いに影響し合います。打ち切り誤差を減らそうとすると丸め誤差の影響が大きくなることがあり、適切なバランスを見つけることが重要です。
数値計算のアルゴリズムを設計する際には、これらの誤差の特性を理解し、適切な対処法を選択することが、正確で効率的な計算のために不可欠です。