桁溢れを想定するのは意外に厄介
オーバーフローは変数のサイズを超えた値を代入すると発生するエラーです。
ただ、ソースコードの裏側で起こる演算に対してのエラーを指す事もあるので注意が必要です。
Microsoft Learn の解釈
Microsoft Learn ではオーバーフローの原因について、3つのケースを紹介していました。
1.割り当て、計算、またはデータ型変換の結果が大きすぎ、変数型に許可されている値の範囲を超えている。
これは単純に変数型の範囲を超えた値を代入しようとして起こるエラーになります。以下のプログラムコードを参考にしてください。
Sub Overflow1()
Dim i As Integer
'Integer型の数値の範囲は「-32,768 ~ 32,767」
i = 33000 'オーバーフロー
End Sub
2.プロパティへの割り当てが最大値を超えている。
プロパティ値を設定する場合もその範囲を超えるような値を代入しようとするとオーバーフローが発生します。
3.計算で数値を使用しようとしたとき、数値が「整数」に強制的に変換され、その結果が「整数」よりも大きくなりました。
イメージしずらいのがこの時の対処になります。Microsoft Learn の例では、以下のようになっています。
Sub Overflow2()
Dim x As Long
'x = 2000 * 365 ' Error: Overflow
x = CLng(2000) * 365 ' OK
Debug.Print x ' 730000
End Sub
一見すると、コメントアウトした計算式でエラーが出るのは何でだろう?となります。
3で言っている内容が、最初は良くわからなかったのですが、「整数」を「Integer型の数値」と読み替えると納得できます。
計算式部分の右辺、2000 も 365 もInteger型の範囲内ですが、計算する事によって、32,767を超えるためにエラーとなるという解釈です。ちなみに、計算式を変更すると以下の様になります。
x = 2000 * 16 x = 32000 でOK。
x = 2000 * 17 x = 34000 でオーバーフロー。
計算式は以下の様に後ろの365をLong型に変更してもOKです。
x = 2000 * CLng(365)
但し、以下の様に右辺を全て括るとオーバーフローが発生します。
x =CLng(2000 * 365) オーバーフロー。
結局、変数 x はLong型でも、代入する際のリテラル(直接記述した数値)の計算結果がInteger型の数値を超えるとオーバーフローになるようです。
右辺の数値を変数に入れてしまえば何も問題ありません。
以下のコードはエラーになりません。
Sub Overflow3()
Dim x As Long, R1 As Long, R2 As Long
R1 = 2000
x = R1 * 365
Debug.Print x
R2 = 365
x = 2000 * R2
Debug.Print x
End Sub
R1,R2はInteger型だとオーバーフローとなります。
除算で0となる例
除算では、計算結果が変数型の範囲を超える場合はもちろんですが、
0で割る(0が分母となる)場合にもオーバーフローが発生します。
この時、分子が0となる場合はオーバーフローが発生し、
分子が0以外で分母が0であれば、「0で除算しました。」が発生するようです。
以下の結果を参考にしてください。
Dim a As Double, d As Long, z As Long
a = 100 / 0 '0で除算しました。
a = 0 / 0 'オーバーフローしました。
a = 0 / 1 'a = 0
d = 0
a = d / 0 'オーバーフローしました。
d = 100
a = d / 0 '0で除算しました。
d = 100
z = 0
a = d / z '0で除算しました。
d = 0
z = 0
a = d / z 'オーバーフローしました。
まとめ
オーバーフローで分かりずらいのは、式の右辺で整数(Integer型の数値)を超えた場合の対処だと思います。
対処する場合は、右辺の値を変数に置き換えるなどして試してみるのが良いかと思います。
また0で除算してしまった場合、必ず「0で除算しました。」というエラーが出るわけではなく、分子が0となっていればオーバーフローが発生します。