bad_if.py プログラム技術ドキュメント

プログラムの動作

この bad_if.py プログラムは、浮動小数点数の計算における精度問題を示すために設計されています。具体的には、ある浮動小数点数 \(h\)\(n\) 回繰り返し加算した結果 \(v\) が、理論上の期待値 \(answer\) と厳密に一致するか、およびある許容誤差 \(eps\) の範囲内で一致するかを検証します。

プログラムは、コマンドライン引数として加算する値 \(h\)、加算回数 \(n\)、および期待される結果 \(answer\) を受け取ります。これらの引数が指定されない場合、プログラムは内部で定義されたデフォルト値を使用します。計算後、v の値、v == answer の厳密な比較結果、そして |v - answer| < eps の浮動小数点誤差を考慮した比較結果を標準出力に表示します。これにより、浮動小数点演算の特性上、厳密な等号比較が意図しない結果を返す可能性があることを示します。

原理

本プログラムの核となる原理は、コンピュータにおける浮動小数点数の表現と演算に起因する丸め誤差です。一般に、多くの実数は浮動小数点形式で正確に表現することができません。例えば、10進数の \(0.1\) は2進数では無限小数となり、有限のビット数では近似値として表現されます。

この近似表現に起因して、浮動小数点数を繰り返し加算すると、微小な誤差が累積します。結果として、\(h \times n\) が理論上の正確な値であったとしても、実際の計算結果 \(v\)\(answer\) と厳密には一致しない場合があります。 プログラムは以下の計算を実行します。

  1. \(h\)\(n\) 回加算し、変数 \(v\) に格納します。

    \[v = \sum_{i=1}^{n} h\]
  2. 計算結果 \(v\) と期待値 \(answer\) の厳密な比較を行います。

    \[v == answer\]
  3. 計算結果 \(v\) と期待値 \(answer\) の差の絶対値が、許容誤差 \(eps\) より小さいかを比較します。

    \[|v - answer| < eps\]

浮動小数点数の比較においては、厳密な等号比較(\(==\))ではなく、許容誤差を用いた比較(\(|a - b| < \text{epsilon}\))が一般的に推奨されます。このプログラムはその違いを実演します。

必要な非標準ライブラリとインストール方法

本プログラムはPythonの標準ライブラリのみを使用しており、非標準ライブラリは必要ありません。 したがって、追加のインストール作業は不要です。

必要な入力ファイル

本プログラムは入力ファイルを必要としません。 すべての入力はコマンドライン引数として直接提供されます。

生成される出力ファイル

本プログラムは出力ファイルを生成しません。 すべての結果は標準出力(コンソール)に表示されます。

コマンドラインでの使用例 (Usage)

bad_if.py は以下の形式でコマンドラインから実行します。

python bad_if.py [h] [n] [answer]
  • h: 加算する浮動小数点数。省略した場合のデフォルト値は 0.01

  • n: 加算する回数。省略した場合のデフォルト値は 100

  • answer: 期待される結果となる浮動小数点数。省略した場合のデフォルト値は 1.0

引数を指定しない場合や、引数が不足している場合は、プログラムの用法メッセージが表示されます。

コマンドラインでの具体的な使用例

  1. デフォルト値での実行: 引数を指定せずに実行すると、プログラムはデフォルト値 (h=0.01, n=100, answer=1.0) を使用します。

    python bad_if.py
    

    実行結果の説明: この場合、\(0.01\)\(100\) 回足し合わせる計算が行われます。理論的には結果は \(1.0\) となりますが、多くの環境で浮動小数点誤差のため、厳密な比較では \(False\) となります。しかし、許容誤差内の比較では \(True\) となるでしょう。典型的な出力は以下のようになります。

    Summing up 0.01 for 100 times: v = 0.9999999999999999
    v == 1.0?: False
    |v - 1.0| < 1.0e-10?: True
    
  2. 誤差が明確に出るような値を指定して実行: h\(0.1\)n\(10\)answer\(1.0\) として実行します。

    python bad_if.py 0.1 10 1.0
    

    実行結果の説明: \(0.1\)\(10\) 回足し合わせると理論上は \(1.0\) ですが、\(0.1\) は2進数で正確に表現できないため、このケースでは浮動小数点誤差が明確に現れ、厳密な比較が False になる典型的な例です。

    Summing up 0.1 for 10 times: v = 0.9999999999999999
    v == 1.0?: False
    |v - 1.0| < 1.0e-10?: True