[VBA] Mod 演算子で割り算の余りを求める

 VBA では割り算の剰余を求めるために、関数ではなく Mod 演算子が用意されています。エクセルの MOD関数とは少し使い勝手が異なりますが、基本的な考え方は同じです。

Mod演算子

 VBA の Modモジュロ演算 (剰余演算) を実行します。
 a を b で割ったときの余りを求めて変数 i に代入するときは

i = a Mod b

のように記述します。たとえば 11 を 4 で割ったときの余りを求めるには次のようなコードを書きます。

'[VBA] Mod演算子のサンプルコード[1]
Sub Modulo_1()
  Dim i As Integer
  i = 11 Mod 4
  Debug.Print i
End Sub
3

MODの演算結果① a, b が非整数の場合

 Mod演算子のステートメント

i = a Mod b

において b が 0 の場合は( 0 で割ることになるので)エラーになるのは言うまでもありません。また a や b が整数でない場合はエラーにはなりませんが、銀行丸め によって強制的に整数に変えて計算を続行します。

 銀行丸めは四捨五入とよく似ています。 10.3 であれば 10 に丸め、10.7 であれば 11 に丸めます。ただし 10.5 のときは「偶数である」10 のほうへ丸められます。 11.5 であれば「偶数である」12 のほうへ丸められます。たとえば 11 ÷ 2.5 という計算を考えたときに、

i = 11 Mod 2.5

と書くと、得られる値は 11 ÷ 2 を計算して余り「 1 」を得ます(四捨五入であれば 11 ÷ 3 の余りは 2 となるはずです)。実際に計算させるマクロを載せておくので試してみてください。

'[VBA] Mod演算子のサンプルコード[2]
Sub Modulo_2()
  Dim i As Integer
  i = 11 Mod 2.5
  Debug.Print i
End Sub
1

MODの演算結果② a, b が負の場合

 整数論の話になりますが、11 を -2 で割ったときの商は -5 ですから、

11 = (-5) × (-2) + 1

のように書くことができます。この + 1 という部分が余りですから、VBA で

i = 11 Mod -2

とすれば「 1 」を得ることになります。同じように -11 を 3 で割ったときの商は -3 なので、

-11 = (-3) × 3 - 2

と書けて、余りが -2 であることがわかります。 VBA で

i = -11 Mod 3

と記述すると「 -2 」が返ります。実際のコードは次のようになります。

'[VBA] Mod演算子のサンプルコード[3]
Sub Modulo_3()
  Dim i As Integer
  i = -11 Mod 3
  Debug.Print i
End Sub
-2

ベキ乗の除算の余りを求める手順

 たとえば VBA の Mod 演算子で $2^{100}$ を $13$ で割ったときの余りを求めようと思って、次のようなコードを書いたとします。

'[VBA] Mod演算子のサンプルコード[4]

'2^100を13で割ったときの剰余を計算するマクロ
Sub Modulo_4()
  Dim x As Long
  Debug.Print (2 ^ 100) Mod 13
End Sub

 Modulo_4() を実行するとオーバーフローしてしまいます。巨大数 $2^{100}$ の演算が VBA の処理能力を遥かに超えてしまうからです。しかし、数論の合同式を上手く活用すると、$a^k$ のような整数のベキ乗を除算したときの余りはたった数行のコードで計算できます。アルゴリズムの流れを確認するために、例として $5^8$ を $7$ で割ったときの余りを合同式で求めてみます。計算には合同式の基本公式
 
\[a\equiv b,\:\:c\equiv d\quad\Longrightarrow\quad ab\equiv cd\quad\pmod m\]
を用います。
 
\[5\equiv 5\quad\pmod 7\]
はもちろん成り立ちます。両辺に $5$ を掛けると
 
\[5^2\equiv 25\equiv 4\quad\pmod 7\]
となります。以下同様に両辺に $5$ を掛け続けます。
 
\[\begin{align*}&5^3\equiv 20\equiv 6&\quad\pmod 7\\[6pt]
&5^4\equiv 30\equiv 2&\quad\pmod 7\\[6pt]
&5^5\equiv 10\equiv 3&\quad\pmod 7\\[6pt]
&5^6\equiv 15\equiv 1&\quad\pmod 7\\[6pt]
&5^7\equiv 5&\quad\pmod 7\\[6pt]&5^8\equiv 25\equiv 4&\quad\pmod 7\end{align*}\]
 よって余りは $4$ となります。この方法で $a^k$ を除算したときの余りを計算する MOD_P 関数のコードを載せておきます。

'[VBA] Mod演算子のサンプルコード[5]

'a^kをmで割ったときの余りを計算する関数
Function MOD_P(a As Long, k As Long, m As Long)
  Dim i As Long, x As Long
  x = 1
  For i = 1 To k
    'xにaを掛けてmで割って余りを求める
    x = a * x Mod m
  Next i
  MOD_P = x
End Function

 MOD_P 関数をワークシートで使用するときは

=MOD_P(a,k,m)

と入力します。たとえば $5^8$ を $7$ で割ったときの余りを計算させるときは

=MOD_P(5,8,7)

と入力すると「4」が返ります。もっと大きな数で試してみましょう。 $2^{100}$ を $13$ で割ったときの余りを計算させてみます。

=MOD_P(2,100,13)

と入力すると「3」が返ります。

コメント

タイトルとURLをコピーしました