VBA

最近、AccessをいじったりPHPをいじったりと頭が混乱しそうです(^_^;)

そんな中、Accessの開発を行っていたら何やら不可思議な現象が発生!その問題というのは下記プログラムです。


Public Function test()
	Dim dblA As Double
	Dim dblB As Double

	dblA = 0.15
	dblB = 0.1 * 1.5

	If dblA = dblB Then
		MsgBox "AとBは同じです。"
	ElseIf dblA  > dblB Then
		MsgBox "Aの方がBより大きいです。"
	ElseIf dblA <  dblB Then
		MsgBox "Bの方がAより大きいです。"
	End If
End Function

プログラムそのものはわかりやすく改変していますが、その問題を確認することはできます。
VB(A)がわからないプログラマでも上記プログラムならそれほど難しくないことでしょう。

さて、上記プログラムを実行するとメッセージボックスが表示されるのですが、どのようなメッセージが表示されるでしょうか?プログラムがわかる人なら「これ」と直ぐに答えられるでしょうし、今回、はまってしまった問題はどの部分なのかがわかる人はそれなりに経験している人でしょうね。

さてさてその問題というのは・・・( ̄ー ̄)ニヤリ

まずはプログラムがわからない人のためにプログラムの説明を書こうと思ったのですが、非常に長くなるので上記のプログラムを日本語化して説明したいと思います。


' ここから「test」という関数のスタートだよ!
Public Function test()
	' 「dblA」という倍精度浮動小数点数型の箱を用意します
	Dim dblA As Double
	' 「dblB」という倍精度浮動小数点数型の箱を用意します
	Dim dblB As Double

	' 「dblA」という箱に0.15という数字を入力します
	dblA = 0.15
	' 「dblB」という箱に0.1×1.5の計算結果を入力します
	dblB = 0.1 * 1.5

	' 「dblA」と「dblB」の値が同じなら次の行を実行しなさい
	If dblA = dblB Then
		' 「AとBは同じです。」というメッセージを表示しなさい
		MsgBox "AとBは同じです。"
	' 先ほどの条件が一致しない場合で
	' 「dblA」の方が「dblB」よりも大きい場合は次の行を実行しなさい
	ElseIf dblA  > dblB Then
		' 「Aの方がBより大きいです。」というメッセージを表示しなさい
		MsgBox "Aの方がBより大きいです。"
	' 更に先ほどの条件が一致しない場合で
	' 「dblB」の方が「dblA」よりも大きい場合は次の行を実行しなさい
	ElseIf dblA <  dblB Then
		' 「Bの方がAより大きいです。」というメッセージを表示しなさい
		MsgBox "Bの方がAより大きいです。"
	' ここで分岐条件は終わりです
	End If
' 関数はここで終わりです。
End Function

まあ、プログラムがわかる人にとっては特に難しいことはないでしょう。上記の説明で「倍精度浮動小数点数」というのが出てきますが、これは簡単に言うと小数点用の箱と思っておけばいいでしょう。

さて、上記プログラムをExcelやAccessの標準モジュールに入れてイミディエイトウィンドで「Call test」とすればプログラムは実行されます。その実行の前に上記のプログラムの結果はどのようなメッセージが出るでしょうか?おそらく多くの人が

AとBは同じです。

と表示されると思いますよね。私も最初はそう思っていました。「違う!」という人は流石ですね。結果は

Bの方がAより大きいです。

になります。「何で?」と思う人は下記答えを見ないで私と同じように2時間ほど悩みましょう(笑)

プログラム上は変数dblAに0.15が入って、dblBに0.1×1.5の計算結果である0.15が入っていると思いがちなのですが、実はdblBには0.15が入っていないのです。

これはよくある小数点の誤差と言う奴です。0.1×1.5というのは通常ならそのままの計算で0.15となりそうなのですが、0.1側に問題があります。

コンピュータは小数点の計算、扱いが苦手で0.1を0.1として扱ってくれません。0.1の場合は

0.10000000000000000055511151231257827021181583404541015625

という数字になってしまうのです。(上記数字であっていると思うけど・・・)。この理由に関しては非常に難しくてとても説明できません。なのでこちらのページを見て頂ければその説明が詳しく書かれています。

これでわかりますよね。dblBに入った数字は0.1×1.5の答えの0.15ではなく0.100000000000000000555・・・×1.5の答えの0.150000000000000000832667268468になるのです。その為、dblAの0.15とdblBに入った0.150000000000000000832667268468を比較すればdblBが大きいのは当たり前。

小数点の誤差は知っていましたが、この問題がそうだとは気が付かずに長い時間悩んでしまいました。まして、それぞれの変数dblA、dblBの中身をチェックしても変数内には両方とも「0.15」と表示されるのです。知っていれば大したことはないですが、これを見つけるのは結構大変でした(^_^;)。同じような問題に遭遇した方は参考になれば幸いです。

コンピュータはなぜ動くのか~知っておきたいハードウエア&ソフトウエアの基礎知識~
矢沢 久雄 日経ソフトウエア
日経BP社
売り上げランキング: 2353