[VB.NET] 期待通りに丸められない場合がある

2014年1月2日

 浮動小数点型を使用した丸め処理を行う場合、意図しない結果になる場合があります。
 たとえば以下。5.015 を小数点以下2桁としたいので、期待する結果は 5.02 ですが、結果は 5.01 になります。

Dim r As Double

r = 5.015R
r = Math.Round(r, 2)
Console.WriteLine("{0}", r)

 結果(期待値は 5.02)

5.01
続行するには何かキーを押してください . . .

 似たようなコードはいくらでも作れて、以下のようなコードでも期待する結果と異なります。

Dim r As Double

r = 1.001
r = r * 1000
r = Math.Floor(r)
r = r / 1000
Console.WriteLine("{0:0.000}", r)

 結果(期待値は 1.001)

1.000
続行するには何かキーを押してください . . .

 要するに、浮動小数点型は 10 進数的には近似表現になっている場合があり、それを意識せずに処理すると意図しない結果になりますよ、ということなのですが、Math.Round のような標準関数でも起こりうるという点には注意が必要です。

 そもそも浮動小数点型の値に、この手の厳密さが必要か?という話もありますが、万一ここを厳密に…という場合は、一度 decimal に代入してやると解決します。

Dim r As Double
Dim d As Decimal

r = 5.015R
d = r
r = Math.Round(d, 2)
Console.WriteLine("{0}", r)

r = 1.001
d = r
d = d * 1000
d = Math.Floor(d)
r = d / 1000
Console.WriteLine("{0:0.000}", r)

 結果

5.02
1.001
続行するには何かキーを押してください . . .

 速度的には ? なところがありますが、とりあえず 10進数的な精度を出したい、という場合はこれで対処できます。(多分 -_-;)

 しかし、浮動小数点型を使っている時点で、上記でいえば 5.015 や 1.001 を得る以前の段階でいろいろな誤差を生じている可能性があり、ここだけをお手当てしても全体的な精度という意味では上がりません。命令単体ではなく、演算全体で精度をどうするか、演算全体で、浮動小数点型が有利なのか、decimal が有利なのか、混在させたほうがよいのかを判断する必要があります。


 今回参考にしたサイト) http://d.hatena.ne.jp/hnw/20131229






カテゴリー: Program, VB.NET

Follow comments via the RSS Feed | Leave a comment | Trackback URL

コメントを投稿する

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


«   »
 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org