エクセルには、割り算の余りを求めるMOD関数というのがあります。
MOD関数はワークシート上で使える関数で、割り算の余りを求めるだけでなく、対象の数値の特性を調べるのにも使えます。
一方、VBAでは似た機能を持つMOD演算子というものがあります。
割り算の余りを求めるというのは同じですが、整数しか扱えず、小数が入力されると少しやっかいなことが起こります。
本記事では、「VBAでMOD演算子を用いて、偶数・奇数判定や素数判定を行なう方法」について、MOD演算子のクセも踏まえて解説します。
MOD関数をワークシート上で用いる事例については、別記事「エクセルで割り算の余りを求める方法!MOD関数の使用例を解説」で取り扱っていますので、併せてご覧ください。
1.VBAでのMOD演算子
こんにちは。エクセルマン・ブリーダーのしもむぎ(@re_znd13)です。
1.1 MOD演算子の構文
まずはVBAでMOD演算子を使う場合の構文を見てみましょう。
result = number1 Mod number2
number1は被除数、number2は除数です。
ワークシート上でのMOD関数(=MOD(被除数,除数))と異なり、算数や数学などでの「被除数 ÷ 除数」という記述と同じ順で、÷の記号をMODに置き換えたような記述となります。
1.2 MOD演算子のクセ
最初に少し触れましたが、MOD演算子には少しやっかいなクセがあります。
MicrosoftのMOD演算子のドキュメントには、被除数・除数について「浮動小数点数の場合は、まず整数に四捨五入されます。」と書かれています。
この中に2つの癖があります。
ひとつは「小数を整数に四捨五入する」という点。
もうひとつは「四捨五入が銀行丸めである」という点。
ひとつめはそういうものかと納得できそうですが、問題はふたつめの「銀行丸め」です。
この聞き慣れない「銀行丸め」とは、最近接偶数への丸めとも呼ばれていて、5の扱いが特殊です。
通常の四捨五入では5は切り上げますが、「銀行丸め」の場合、結果が偶数になる方に丸めます。
1.5を小数点第一位で銀行丸めすると2、2.5を小数点第一位で銀行丸めすると2となるのです。
上記ドキュメントには「銀行丸め」である旨が書かれていませんが、ROUND関数のドキュメントには記載があります。
別記事「ROUND関数にバグ?VBAの四捨五入で失敗しない2つの方法」でROUND関数での検証をしていますので、併せてご覧ください。
これらのクセを検証するために、以下のVBAコードで計算例を見てみましょう。
Sub MOD演算子()
MsgBox 10 Mod 5 'ケース1:整数÷整数
MsgBox 10 Mod 3 'ケース2:整数÷整数
MsgBox 12 Mod 4.3 'ケース3:整数÷小数
MsgBox 12.6 Mod 5 'ケース4:小数÷整数
MsgBox 9 Mod 4.5 'ケース5:整数÷小数
End Sub
ケース1は、整数同士の割り算で、結果は0になるはずですね。
MOD演算子を使った結果でも、整数同士なので、正しく0という余りが求められました。
ケース2も整数同士の割り算です。
結果は1となり、正しく求められています。
ケース3は、整数÷小数というケース。
本来は余りが3.4となるところですが、除数の4.3が4として扱われて余り0という結果になります。
ケース4は、小数÷整数というケース。
本来は余りが2.6となるところですが、被除数の12.6が13として扱われて余り3という結果になります。
ケース5は整数÷小数というケース3と同様のケースで、本来は割り切れるので余り0となる式です。
しかし除数4.5は四捨五入で整数になり、さらにその四捨五入は銀行丸めですので、偶数になるように丸められ4として扱われます。
したがって、余り1という結果になります。
このように、小数を扱う割り算においてVBAのMOD演算子は使いにくいことがわかりました。
2.MOD演算子の使用例
2.1 偶数・奇数判定
ここからは整数を扱うという前提で、VBAにおけるMOD演算子の使用例を考えてみましょう。
最初の例では偶数か奇数の判定について考えてみます。
偶数・奇数といえば、「2で割り切れるかどうか」で判断できますよね。
ある数値を被除数、除数を2としたときにMOD演算子で求まる値が0だと偶数、1だと奇数だと言えます。
このことを利用して、以下のようなVBAコードを組んでみました。
Sub 偶数奇数判定()
'A 型の宣言
Dim i As String
'B ユーザ入力とエラー回避
i = InputBox("任意の整数を入力してください")
If StrPtr(i) = 0 Then
Exit Sub ' キャンセル時に終了
End If
'C エラー回避
If IsNumeric(i) = False Then
MsgBox "入力値が数値ではありません"
Exit Sub '数値でない場合に終了
ElseIf i <> Int(i) Then
MsgBox "入力値が整数ではありません"
Exit Sub '整数でない場合に終了
End If
'D 偶数・奇数判定
If i Mod 2 = 0 Then
MsgBox i & "は偶数です"
Else
MsgBox i & "は奇数です"
End If
End Sub
Aパートでは、データの型を宣言しています。
次のパートでユーザー入力されるものをString型(文字列型)とし、整数以外は警告を出しつつプログラムを終了するようにしています。
Bパートでは、インプットボックスを使ってユーザーに任意の整数を入力してもらうよう促します。
インプットボックスではキャンセルが押されると「型が一致しません」とエラーが出てしまうので、キャンセル時はプログラムを終了するようにしました。
Cパートでは、整数以外を入力された場合のエラーを回避する内容です。
IsNumeric関数は数値かどうかを判定するもので、数値でない(False)場合には「あ」や「a」などの文字列が入力されたと判断してプログラムを終了します。
Int関数は引数の小数部分を取り除いて整数を返すもので、元の数値と整数部分が一致していない場合には小数が入力されたと判断してプログラムを終了します。
Dパートでは、入力された整数を被除数、固定値2を除数としたときの余りが0であればメッセージボックスに偶数である旨を表示、そうでない場合には奇数である旨を表示させます。
下の画像は255を入力したときの結果です。
別記事「エクセルで割り算の余りを求める方法!MOD関数の使用例を解説」では、ワークシート関数としてのMOD関数を使用して、同様のことをできるようにしていますので、併せてご覧ください。
2.2 素数判定
次に、素数かどうかの判定について考えてみます。
素数というのは、「1より大きい自然数で、正の約数が1と自分自身のみであるもの」とされています。
つまり、対象の値を1より大きい自然数で割ったときに、割り切れる組合せがない(余り0の組合せがない)ならば素数といえる、ということです。
このことを利用して、以下のようなVBAコードを組んでみました。
Sub 素数判定()
'A 型の宣言
Dim i As Long
Dim n As String
'B ユーザ入力とエラー回避
n = InputBox("1より大きい自然数を入力してください")
If StrPtr(n) = 0 Then
Exit Sub ' キャンセル時に終了
End If
'C エラー回避
If IsNumeric(n) = False Then
MsgBox "入力値が数値ではありません"
Exit Sub '数値でない場合に終了
ElseIf n <> Int(n) Then
MsgBox "入力値が整数ではありません"
Exit Sub '整数でない場合に終了
End If
'D 素数判定
If n >= 2 Then
For i = 2 To n - 1
If n Mod i = 0 Then
MsgBox n & "は素数です"
Exit For
ElseIf i = n - 1 Then
MsgBox n & "は素数ではありません"
End If
Next i
Else
MsgBox "1より大きい自然数ではありません"
End If
End Sub
Aパートでは、データの型を宣言しています。
iはループ用の変数でLong型としました。
nは次のパートでユーザー入力されるものをString型(文字列型)とし、1より大きい自然数以外は警告を出しつつプログラムを終了するようにしています。
Bパートでは、インプットボックスを使ってユーザーに1より大きい自然数を入力してもらうよう促します。
インプットボックスではキャンセルが押されると「型が一致しません」とエラーが出てしまうので、キャンセル時はプログラムを終了するようにしました。
Cパートでは、整数以外を入力された場合のエラーを回避する内容です。
IsNumeric関数は数値かどうかを判定するもので、数値でない(False)場合には「あ」や「a」などの文字列が入力されたと判断してプログラムを終了します。
Int関数は引数の小数部分を取り除いて整数を返すもので、元の数値と整数部分が一致していない場合には小数が入力されたと判断してプログラムを終了します。
Dパートでは、入力された値が2以上である場合に、iを2から(入力値-1)まで変えながら、n÷iの余りが0(割り切れる)の場合に、メッセージボックスにて素数である旨を表示、そうでない場合に素数でない旨を表示するとして、ループ処理します。
下の画像は123454321を入力したときの結果です(以外に素数でした!)。
別記事「エクセルで割り算の余りを求める方法!MOD関数の使用例を解説」では、ワークシート関数としてのMOD関数を使用して、これより少し簡易なことをトライしていますので、併せてご覧ください。
3.まとめ
本記事では、「VBAでMOD演算子を用いて、偶数・奇数判定や素数判定を行なう方法」について解説しましたが、いかがでしたか?
小数を扱うときは整数になること、それが銀行丸めの四捨五入であるというMOD演算子のクセも注意したいですね。