bad_if.py プログラムの技術ドキュメント
プログラムの動作
bad_if.py は、浮動小数点数の累積加算における精度問題と、それによる厳密な等値判定の困難さを示すために設計されたPythonスクリプトです。このプログラムは、コマンドライン引数として「加算する値 $h$」、「加算回数 $n$」、「期待される合計値 answer」を受け取ります。
主な機能は以下の通りです。
コマンドライン引数、またはプログラム内で定義されたデフォルト値(
h=0.01,n=100,answer=1.0)に基づき、hをn回繰り返し加算します。計算された合計値
$v$がanswerと厳密に等しいかどうかを判定し、結果を表示します。計算された合計値
$v$とanswerの差の絶対値が、定義された許容誤差eps(デフォルト値は \(1.0 \times 10^{-10}\))よりも小さいかどうかを判定し、結果を表示します。
これにより、例えば \(0.01\) を \(100\) 回加算しても厳密に \(1.0\) にならない可能性を具体的に示し、浮動小数点数の比較には許容誤差を用いるべきであるという教訓を提供します。
原理
このプログラムの核心は、コンピュータにおける浮動小数点数(通常はIEEE 754標準に基づく二進浮動小数点数)の表現と演算の特性にあります。
浮動小数点数の近似表現: 多くの十進数(例: \(0.1, 0.01\))は、二進数では有限の桁数で正確に表現できません。これらは最も近い二進表現に丸められて格納されます。この時点でわずかな誤差が発生します。
累積誤差:
$h$を$n$回加算する際、各加算ステップで発生する微小な丸め誤差が累積されます。理想的には \(v = h \times n\) となるはずですが、実際の計算では \(v_{\text{calc}} \ne h \times n\) となることがしばしばあります。厳密な等値判定の問題: 上記の理由から、浮動小数点数の厳密な等値判定
$v_{\text{calc}} == \text{answer}$は、期待通りに機能しないことがほとんどです。たとえ人間が期待する結果が$h \times n = \text{answer}$であったとしても、コンピュータ内部での$v_{\text{calc}}$がanswerとごくわずかに異なるため、この比較はFalseを返します。許容誤差 (Epsilon) による比較: 浮動小数点数の比較を行う際の推奨される方法は、両者の差が特定の小さな値(許容誤差
eps)よりも小さいかどうかをチェックすることです。プログラムでは、この比較は以下の数式で表されます。\[ |v_{\text{calc}} - \text{answer}| < \text{eps} \]ここで、
epsはプログラム内で \(1.0 \times 10^{-10}\) と定義されています。この方法であれば、たとえ$v_{\text{calc}}$がanswerと厳密には一致しなくても、実用上許容できる範囲内の差であればTrueと判断できます。
必要な非標準ライブラリとインストール方法
bad_if.py はPythonの標準ライブラリである sys のみを使用しています。そのため、特別な非標準ライブラリは必要ありません。
したがって、インストールすべき追加のライブラリはありません。
必要な入力ファイル
bad_if.py は、外部の入力ファイルを必要としません。すべての入力はコマンドライン引数として提供されます。
プログラムが期待する引数は以下の通りです。
h: (浮動小数点数) 加算される値。省略された場合のデフォルト値:
0.01
n: (整数)hを加算する回数。省略された場合のデフォルト値:
100
answer: (浮動小数点数) 比較対象となる期待値。省略された場合のデフォルト値:
1.0
引数が提供されなかった場合、プログラムは内部で定義されたデフォルト値を使用します。
生成される出力ファイル
bad_if.py は、いかなるファイルも生成しません。すべての結果は標準出力 (stdout) に表示されます。
出力される内容は以下の情報を含みます。
加算に使用された
h、nの値。実際に計算された合計値
$v$。厳密な等値判定の結果 (
v == answer)。許容誤差
epsを用いた比較の結果 (abs(v - answer) < eps)。
出力形式は以下のようになります。
Summing up {h} for {n} times: v = {v}
v == {answer}?: {厳密な比較結果}
|v - {answer}| < {eps}?: {許容誤差での比較結果}
コマンドラインでの使用例 (Usage)
bad_if.py は、以下の形式でコマンドラインから実行します。
python bad_if.py [h] [n] [answer]
h: 加算する浮動小数点数(例:0.01)n: 加算回数(例:100)answer: 比較対象の期待値(例:1.0)
各引数はオプションであり、省略された場合はプログラム内部で定義されたデフォルト値が使用されます。ただし、引数を全く指定しない場合や、h のみ指定した場合など、引数が h と n の2つ未満の場合は、プログラムは以下のようなUsageメッセージを表示して終了します。
Usage: python bad_if.py h n answer
Check the condition h * n == answer
コマンドラインでの具体的な使用例
1. 引数を全く指定しない場合
h と n の引数が不足しているため、Usageメッセージが表示されます。
python bad_if.py
実行結果:
Usage: python bad_if.py h n answer
Check the condition h * n == answer
2. デフォルト値が適用される引数で実行する場合
h=0.01 を n=100 回加算し、結果が answer=1.0 となるか検証します。浮動小数点数の精度問題により、厳密な比較は False となります。
python bad_if.py 0.01 100 1.0
実行結果:
Summing up 0.01 for 100 times: v = 0.9999999999999999
v == 1.0?: False
|v - 1.0| < 1.0e-10?: True
3. 別の浮動小数点数の例で実行する場合
h=0.1 を n=10 回加算し、結果が answer=1.0 となるか検証します。この場合も、厳密な比較は False となります。
python bad_if.py 0.1 10 1.0
実行結果:
Summing up 0.1 for 10 times: v = 0.9999999999999999
v == 1.0?: False
|v - 1.0| < 1.0e-10?: True