逆行列Subプロシージャの作成
Subプロシージャは、企業が特定の専門分野を分社化したときの子会社に例えられるものであり、プ
ログラムにおける部品に例えることもできるものである。特定の処理を行うプログラム部分をSubプロ
シージャ化(部品化)しておけば、別のプログラムにおいて同じ処理が必要になったとき、先に作って
おいたSubプロシージャを組み込むことでプログラムを簡単に作成することができる。Subプロシージャ
が多数用意されていれば、必要なSubプロシージャを組み合わせるだけで目的のプログラムを作成する
ことも可能になる。また、Subプロシージャそれぞれを個別に完成させることは、全体を同時に作成す
ることよりも容易であるため、巨大なプログラムを作成する際には、全体を多数のSubプロシージャに
分割して作成する方法が採られている。
個別のSubプロシージャを作成するときに決めるべきことは、
・Subプロシージャ名
・Subプロシージャが行うべき処理
・引数
のみである。ここで、「引数」とは当該Subプロシージャが受け取るデータと処理後に戻すデータのこ
とであり、普通はこれらのデータを格納する変数名が使用される。
Subプロシージャの例は、次のようなものである。
Sub abc(x, y, z)
:
End Sub
ここで、abc がSubプロシージャ名であり、x, y, z が引数である。また、このSubプロシージャを呼び
出す命令は
Call abc(p, q, r)
である。ここで注目すべきことは、呼び出す側とSubプロシージャ側の引数のことである。ここでの例
のように、引数に使う変数の名前は異なっていてもかなわない。ただし、個数は一致していなければな
らず、1番目の引数同士、2番目の引数同士および3番目の引数同士は、同じものを別名で指し示すこ
とになる。したがって、Subプロシージャ側で引数として受け取った変数を書き換えたとき、呼び出し
た側で引数として送り出した変数も書き換えられる。しかし、引数以外の変数は、両者で同じ名前の変
数が用いられていたとしてもまったく無関係なものとなる。このことから、Subプロシージャ側では、
使用しようとしている変数名が、他の部分でどのように使われているかをまったく気にせずに使うこと
ができる。このこともSubプロシージャが多用される理由の一つである。
Subプロシージャを呼び出すとき
Call abc(p, a + b, 10)
のように、引数として数式や定数を使うこともできる。ただし、Subプロシージャ側では、これらの受
け皿として変数を用いなければならない。また、ここでの引数pが配列であるとき、Subプロシージャ
側の引数xは自動的に配列となり、xを配列宣言する必要がない。
数式や定数以外の引数は、Subプロシージャに引き渡すものか、Subプロシージャから結果として戻さ
れるものかの区別がなく、プログラムにおいてそれらをどのように使用するかによって決まる。
「逆行列を計算する問題」で作成した以下のExcelマクロで、逆行列計算の部分をSubプロシージャ化
する問題を考えてみる。
|
Sub Mocro1() |
第
1
ブ
ロ
ッ
ク
|
n = ActiveCell: ActiveCell.Offset(1, 0).Range("A1").Select
nn = n + n
ReDim A(n, nn)
For i = 1 To n
For j = 1 To n
A(i, j) = ActiveCell: ActiveCell.Offset(0, 1).Range("A1").Select
Next j
ActiveCell.Offset(1, -n).Range("A1").Select
Next i
ActiveCell.Offset(1, 0).Range("A1").Select
|
第
2
ブ
ロ
ッ
ク
|
For i = 1 To n
For j = n + 1 To nn: A(i, j) = 0: Next j: A(i, i + n) = 1
Next i
'
For k = 1 To n
p = 0.0000000001: c = 0
For i = k To n
If Abs(A(i, k)) > p Then p = Abs(A(i, k)): c = i
Next i
If c = 0 Then ActiveCell = "逆行列が存在しない": GoTo xyz
If c <> k Then
For j = k To nn
y = A(k, j): A(k, j) = A(c, j): A(c, j) = y
Next j
End If
x = A(k, k): For j = k To nn: A(k, j) = A(k, j) / x: Next j
For i = 1 To n
If i <> k Then
x = A(i, k)
For j = k To nn: A(i, j) = A(i, j) - x * A(k, j): Next j
End If
Next i
Next k
|
第
3
ブ
ロ
ッ
ク
|
'
For i = 1 To n
For j = n + 1 To nn
ActiveCell = A(i, j): ActiveCell.Offset(0, 1).Range("A1").Select
Next j
ActiveCell.Offset(1, -n).Range("A1").Select
Next i
xyz: |
|
End Sub |
このプログラムは、データを読み取る部分(第1ブロック)、逆行列を計算する部分(第2ブロック)
および結果を書き出す部分(第3ブロック)で構成されている。ここで、逆行列を計算する部分である
第2ブロックをSubプロシージャ化することにする。
第2ブロックのプログラムにおいて、受け取られなければならないデータ(変数)は、n、nn、Aのみ
である。しかし、nnはnがあれば計算することができるので、引数にする必要がない。引数は多くない
方が好ましいので、ここではnnを引数にしないこととする。また、計算結果はAとcである。cは計算結
果とは言えないかもしてないが、c = 0 のときは逆行列が存在しないことを意味するので、第2ブロッ
クをSubプロシージャ化し、このSubプロシージャを呼び出して戻ってきたときに c = 0 であるかどう
かを判定する必要がある。
Subプロシージャ名をminvとし、引数をn, A, cとして第2ブロックをSubプロシージャ化すると次の
ようになる。
Sub minv(n, A, c)
nn = n + n
For i = 1 To n
For j = n + 1 To nn: A(i, j) = 0: Next j: A(i, i + n) = 1
Next i
'
For k = 1 To n
p = 0.0000000001: c = 0
For i = k To n
If Abs(A(i, k)) > p Then p = Abs(A(i, k)): c = i
Next i
If c = 0 Then Exit Sub
If c <> k Then
For j = k To nn
y = A(k, j): A(k, j) = A(c, j): A(c, j) = y
Next j
End If
x = A(k, k): For j = k To nn: A(k, j) = A(k, j) / x: Next j
For i = 1 To n
If i <> k Then
x = A(i, k)
For j = k To nn: A(i, j) = A(i, j) - x * A(k, j): Next j
End If
Next i
Next k
End Sub
ただし、赤字にした Exit Sub は、Subプロシージャでの処理を終了して強制的に戻るための命令であ
る。一方、本体のプログラムは次のようになる。
Sub Mocro1()
n = ActiveCell: ActiveCell.Offset(1, 0).Range("A1").Select
nn = n + n
ReDim A(n, nn)
For i = 1 To n
For j = 1 To n
A(i, j) = ActiveCell: ActiveCell.Offset(0, 1).Range("A1").Select
Next j
ActiveCell.Offset(1, -n).Range("A1").Select
Next i
ActiveCell.Offset(1, 0).Range("A1").Select
For i = 1 To n
For j = n + 1 To nn: A(i, j) = 0: Next j: A(i, i + n) = 1
Next i
'
Call minv(n, A, c)
If c = 0 Then ActiveCell = "逆行列が存在しない": Exit Sub
'
For i = 1 To n
For j = n + 1 To nn
ActiveCell = A(i, j): ActiveCell.Offset(0, 1).Range("A1").Select
Next j
ActiveCell.Offset(1, -n).Range("A1").Select
Next i
End Sub
ここでは、元々一つプログラムであり、あえて変える必要もないので、引数名が両者で同じになってい
る。
ここで作成したSubプロシージャは
・Subプロシージャ名がminvであること。
・逆行列を計算するSubプロシージャであること。
・引数が三つあること。
・第1引数が行列の大きさを示すこと。
・第2引数は横が縦の2倍の大きさの配列であり、左半分に逆行列を求める行列の値を入力し、
Subプロシージャを呼び出したとき、右半分に逆行列が計算されて戻ってくること。
・第3引数は、逆行列が存在しないとき0、逆行列が存在するとき0以外の値が戻ってくること。
・第1引数は値が変化せず戻ってくるが、第2引数の左半分は単位行列になって戻ってくること。
を覚えておけばよいことになる。
【Excelマクロにおいて、Subプロシージャを作成する方法】
マクロプログラムの最後の行
End Sub
の下に
Sub minv(n, A, c)
のように入力し、Enterキーを押せば
End Sub
―――――――――――――――
Sub minv(n, A, c)
End Sub
となるので、Sub minv行とEnd Sub行の間に必要なプログラムを入力すればよい。
Subプロシージャが作成済みのときは、そのSubプロシージャを使用したいExcelマクロの最後の行
End Sub の下に複写することでもよい。
なお、他のExcelマクロの下に作成済みのSubプロシージャをコピーするとき、同一のExcel上に2つ
以上のマクロ付きファイルを開くと、両方のマクロが競合し、不都合な状況が起こるので、面倒でも、
ファイル1つずつを別のExcelで開くこと。
|