Excel VBA プログラミング 実数を扱うときの落とし穴

2005.9.14 (注意!) このページは 2005.9.14 に書きました。Excel 2003 について 書いたと思われます。 2018.6.25 に Excel 2016 32 bit 版で実験したところ、 異なる結果となります。 以下の記事は Excel 2016 については当てはまりません。 Excel 2016 ではセルに代入するときに丸めは起こりません。 Excel 2016 については こちらを参照してください。 ----------------------------- Excel VBA プログラミングで実数を扱うときの注意について 書きます。 実数型変数とセルは異なる内部表現を持ち、 代入時に何らかの丸めが発生するようです。 コンピュータの世界では数値を 2 進数で表します。 2 進数で表現出来ない数値は循環小数となります。例えば、 10 進数では小数の位は 1 → 0.1 → 0.01 .... と続きますが、 2 進数では小数の位は 1 → 0.5 → 0.25 → 0.125 .... と 続きます。ですから、0.1 は 2 進数では循環小数となり、 0.1 を 10 回足しても 1 にはなりません。 このことはコンピュータで数値計算をする人にとっては常識です。 Excel VBA の Double 型変数や Variant 型変数に対しては この常識が適用されますが、セルが絡むとややこしくなります。 セルのデータは 10 進数表現による内部データ形式を持つようです。 また、セルに Double 型や Variant 型の変数を代入すると、 何らかの丸めが行われるようです。 例えば「0.1 を 10 回足す」ということを実行する以下の プログラムを実行してみて下さい。 ------------------------------------------------ Sub test() Dim i As Long, a As Double, b As Double a = 0 For i = 1 To 10 a = a + 0.1 Next i If a = 1 Then Debug.Print "a = 1" Else Debug.Print "a <> 1" End If Range("A1").Value = a a = Range("A1").Value If a = 1 Then Debug.Print "a = 1" Else Debug.Print "a <> 1" End If End Sub ------------------------------------------------- 0.1 は 2 進数では循環小数ですから、通常は a は 1 にはなりません。 実行してみると 1 回目の if 文では "a <> 1" となり、 2 回目の if 文では "a = 1" となります。 すなわち、値をセルに代入するときに、何らかの丸め処理が行われ るようです。 ですから、 Dim a as double Range("A1").Value = x a = x の場合、セル A1 と a の値は異なるかも知れません。 次の例を見て下さい。 ------------------------------------------------- Sub test2() Dim i As Long, n As Long, a As Double n = 13 a = 0 Range("A1").Value = 0 For i = 1 To n a = a + 0.1 Range("A1").Value = Range("A1").Value + 0.1 Next i If Range("A1").Value = a Then Debug.Print n, "=" Else Debug.Print n, "<>" End If End Sub ------------------------------------------------- Double 型変数 a とセル A1 に 0.1 を n 回足し合わせる プログラムです。結果は次のようになります。 1 = 2 = 3 <> 4 = 5 = 6 = 7 = 8 <> 9 <> 10 <> 11 <> 12 = 13 = イコールになるときとならないときがあります。原因は 良くわかりません。 こんな現象も起こります。 ------------------------------------------------ Sub test() Dim i As Long, a As Double, b As Double, c As Double c = 1 / 5 a = 0 b = 0 For i = 1 To 5 a = a + c b = b + 1 / 5 Next i If a = 1 Then Debug.Print "a = 1" Else Debug.Print "a <> 1" End If If b = 1 Then Debug.Print "b = 1" Else Debug.Print "b <> 1" End If End End Sub ------------------------------------------------ 1 / 5 を数式として書くか、一旦変数 c に代入するかの違いです。 実行してみると何と "a <> 1", "b = 1" となります。この理由は 私には良くわかりません。 このように、Excel でセルが絡んだ実数計算をする場合、 ミステリアスな現象が起こるので、 実数を扱う場合には、他の言語とは異なる注意が必要です。