普通の式で時たま現れる浮動小数値の誤差
小数値の計算では誤差が生じるのは知識として知っていても、あまり出会ったことがない。最近、遭遇したので記録しておく。
0.1を100回足したら10ではないとか、小さな数値と大きな数値を足したら桁落ちするとかではなく、極々普通の式で表面化する誤差の話。
0.1を100回足したら10ではないとか、小さな数値と大きな数値を足したら桁落ちするとかではなく、極々普通の式で表面化する誤差の話。
3.5 + 37.2 + 27.2 + 29.2
4つの数値を足すと97.1なのだが、float型で計算すると「97.10001」になる。
float v1 = 3.5F + 37.2F + 27.2F + 29.2F; System.Diagnostics.Debug.WriteLine(v1); // 97.10001
これはdouble型で計算すれば97.1になるので、普通はあまり出会わない。
double d1 = 3.5 + 37.2 + 27.2 + 29.2; System.Diagnostics.Debug.WriteLine(d1); // 97.1
この「0.5+0.2+0.2+0.2」の式だが、float型で計算してもいつでも誤差が見えるわけではない。
float f1 = 0.5F + 0.2F + 0.2F + 0.2F; System.Diagnostics.Debug.WriteLine(f1); // 1.1 float f2 = 10.5F + 10.2F + 10.2F + 10.2F; System.Diagnostics.Debug.WriteLine(f2); // 41.1 float f3 = 20.5F + 20.2F + 20.2F + 20.2F; System.Diagnostics.Debug.WriteLine(f3); // 81.10001 float f4 = 30.5F + 30.2F + 30.2F + 30.2F; System.Diagnostics.Debug.WriteLine(f4); // 121.1
0.2を3回足すと誤差が生じているようなので、0.2だけを3回足してみた。
float f1 = 0.2F + 0.2F + 0.2F; System.Diagnostics.Debug.WriteLine(f1); // 0.6 float f2 = 10.2F + 10.2F + 10.2F; System.Diagnostics.Debug.WriteLine(f2); // 30.6 float f3 = 20.2F + 20.2F + 20.2F; System.Diagnostics.Debug.WriteLine(f3); // 60.6 float f4 = 30.2F + 30.2F + 30.2F; System.Diagnostics.Debug.WriteLine(f4); // 90.60001 float f5 = 40.2F + 30.2F + 40.2F; System.Diagnostics.Debug.WriteLine(f5); // 110.6
デバッガで実際の数値を見てみると、以下のようになっていた。f1を除いてみな誤差がありまくりだった。しかし表面化しているのはf4だけ。小数点以下6桁目を四捨五入しているのだろうか。でもそれならf5も誤差が表面化するはず。数値として9桁で8桁目を四捨五入している感じ?
40.2 - 40.1
この式は0.1だが、double型で計算しても誤差が表面化してしまう。結果は「0.100000000000001」となる。
double d1 = 40.2 - 40.1; System.Diagnostics.Debug.WriteLine(d1); // 0.100000000000001
なかなか、やっかい。
コメント
コメントを投稿