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 でセルが絡んだ実数計算をする場合、
ミステリアスな現象が起こるので、
実数を扱う場合には、他の言語とは異なる注意が必要です。