はじめMath! Javaでコンピュータ数学

第13回 打ち切り誤差

この記事を読むのに必要な時間:およそ 2 分

解説

(1) 定義式に忠実にソースコードを作成しましょう。

式に忠実にソースコードを作成すると,無限に加算を繰り返すことになります。しかし,現実的にそれは無理ですから計算に意味のあるところまで繰り返すことにします。計算に意味がなくなるのは,ある時点の計算結果と次の時点の計算結果が同じであるという条件にしてみました。無限ループになっては困るので,繰り返し回数はint型の最大値までとしました。以下にそのソースコードを示します。

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
//filename : Uchikiri_Gosa.java
class Uchikiri_Gosa {
  public static void main(String[] args) {
    int i; //counter
    float neip=0; //ネイピア数
    float prev_neip=0;//一つ前に計算したネイピア数
    float kaijyo=1; //階乗値の保管
    for (i=0; i < Integer.MAX_VALUE; i++){
      neip = neip + 1/kaijyo;
      if (prev_neip == neip){
        System.out.println(" final neip is " + neip);
        System.out.println("done...");
        break;
      }
      kaijyo = kaijyo * (i+1);
      System.out.println(i + " neip is " + neip);
      prev_neip = neip;
    }
  }
}

(2) 計算を実行し,何個目の項を加算したところでfloat型の精度いっぱいの値になるか確認しましょう。

実行結果を次に示します。

Uchikiri_Gosa.java の実行結果

0 neip is 1.0
1 neip is 2.0
2 neip is 2.5
3 neip is 2.6666667
4 neip is 2.7083335
5 neip is 2.716667
6 neip is 2.7180557
7 neip is 2.718254
8 neip is 2.718279
9 neip is 2.7182817
10 neip is 2.718282
 final neip is 2.718282
done...

以上の実行結果から,n=10で精度いっぱいの結果を得たことがわかりました。ネイピア数は2.7182818284・ですから,8桁目を四捨五入したと考えれば7桁目まで正確な値を得たと言えます。

n=0から計算を開始しましたから,11項めの加算で終了したのです。12項めは=0.000000025です。左から9桁目にやっと0以外の数値が現れます。n=0の時の第1項めは=1,各項の値は常に正ですから,仮に小数点以上の値がひと桁であってもn=11で必ず加算の際に情報欠落を起こします。これ以上加算を継続する意味がないことがあらかじめわかります。

このように,あらかじめnを適当に選んで計算してみることで,おおよそ何回目で計算が終了するか予想することができます。数値計算に当たっては,プログラムの実行前に計算回数を見立てるよう心がけましょう。それが無駄のない仕事をするために役立ちます。

今回のまとめ

  • 実数型で桁数の多い数値を計算する場合,保管できる桁数に限りがあります。その時に格納できる桁数以上の計算を行っても意味がありません。この見切りの結果発生するのが打ち切り誤差です。

著者プロフィール

平田敦(ひらたあつし)

地方都市の公立工業高等学校教諭。趣味はプログラミングと日本の端っこ踏破旅行。2010年のLotYはRuby。結城浩氏のような仕事をしたいと妄想する30代後半♂。