記事の周囲、または記事中に【広告】が含まれることがあります。

問題

以下のようにVBAで0.044 - 0.042 を計算して、それを小数点第3位で切り捨ててみるとどんな結果が表示されるでしょうか。

小数の計算結果がズレてしまうVBAコード

当然0.002になると思いますよね? でも答えは「0.001」になります(笑)

誤った出力結果

原因

この原因を調べてみると、c = a - b で c の値に0.002と入るところで、0.00199999999... の値が入ってしまい、それを小数点第3位で切り捨てたことで 0.001 という極めて大きな違いになってしまったわけです。

これは、Excel VBA での数値は 10進数ではなく2進数で処理されるため、小数の表現に丸め誤差が生じてしまうからです。

例えば、10進数で 0.002 を2進数で表現すると0 . 0000 0000 1000 0011 0001 0010 0110 1110 1001 0111 1000 1101 0100 1111 といった数字になってしまい、これを10進数に戻してやると(再計算すると) 0.00199999999999998789856903158579370938241481781005859375 となり、0.002 というキリの良い数字ではなくなってしまいます。

これは、ほぼ0.002なので通常利用するうえではそれほど問題にならないかもしれませんが、工業製品の測定値などで有効桁数が小数点第3位切り捨てといった条件下で利用する場合には大きな問題になってきます。

対策

CDec関数による10進数処理

対策としては、CDec関数を使用することで10進数として扱ってやることがシンプルです。ただし、VBAの宣言型にDecimal(10進型)は存在しないので、代入する変数をVariant型として宣言しておきます。

※注意点:一度2進数で処理されてしまうとその後でCDec関数を使っても戻らないので、必ず処理前の小数の段階でCDec関数で10進数扱いにしておきましょう。

小数の計算結果がズレないためにCDec関数を使ったVBAコード

これで計算してみるとc = a - b のところで、0.00199999999... だった c の値が 0.002 となります。

正しいcの値
正しい出力結果

四捨五入による丸め処理

VBAで宣言できない型を使いたくない。小数を扱う度にCDec関数で変換するのが面倒という人もいるかと思います。(いない?)

そういう人向けの対策としては、0.00199999999...を四捨五入する方法になります。ただし、有効桁数で四捨五入にしてしまうと、0.00151402といった値でも0.002(本来は0.001)になってしあうリスクがあるため、有効桁数よりもかなり下の桁で四捨五入して、その後で有効桁数で切り捨てしてやるのが無難だと思います。

小数の計算結果がズレないために四捨五入を使ったVBAコード

これで計算してみるとc = Round(c,10) のところで、先ほどの c の値 0.00199999999... が 0.0020000000 となり、その後の切り捨てでも問題なく 0.002 となります。

正しいcの値
正しい出力結果

まとめ

Excel VBA で小数を扱う場合は、予期せぬ処理ミスが発生することがあります。それを考慮してのプログラミングをおすすめします。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA