第5講 Subプロシージャ

第5話 素数列挙Subプロシージャ

素数列挙マクロコード例
Dim cn As Long


Private Sub CommandButton1_Click()

  Dim n As Long, i As Long

  cn = 0
  n = Cells(5, 2)
  For i = 2 To n
    f (i)
  Next
  Cells(7 + Int(cn / 20), 2) = "素数個数"
  Cells(7 + Int(cn / 20), 3) = cn

End Sub


Sub f(n As Long)

  Dim i As Long, r As Long

  If n = 2 Then
    Cells(6 + Int(cn / 20), 2 + (cn Mod 20)) = n
    cn = cn + 1 
    Exit Sub
  End If

  If n Mod 2 = 0 Then
    Exit Sub
  End If

  r = Sqr(n)
  For i = 3 To r Step 2
    If n Mod i = 0 Then
      Exit Sub
    End If
  Next

  Cells(6 + Int(cn / 20), 2 + (cn Mod 20)) = n
  cn = cn + 1

End Sub


Private Sub CommandButton2_Click()

  Columns("B:U").Select
  Selection.ClearContents
  Cells(1, 1).Select

End Sub

解説
今回は、素数であるか判定し素数である場合のみ表示させています。
注目は
  Cells(6 + Int(cn / 20), 2 + (cn Mod 20)) = n
  cn = cn + 1
の2行です。
Int(cn / 20)は、素数総数cnを20で割った商であり、
cn Mod 20は20で割った余りです。
このようにすると、20個ずつ

表示させることが出来ます。
もし30個ずつ表示させたいときは
Cells(6 + Int(cn / 30), 2 + (cn Mod 30)) = n
とします。要するに、ピンクの数字を変えればよいのです。

今回、グローバル変数を用意しましたが、
次のようにすればローカル変数のみでも出来ます。
Private Sub CommandButton1_Click()

  Dim n As Long

  n = Cells(5, 2)
  f (n)

End Sub


Sub f(n As Long)

  Dim cn As Long
  Dim i As Long, j As Long, r As Long
  cn = 0

  For i = 2 To n
    If i = 2 Then
      Cells(6 + Int(cn / 30), 2 + (cn Mod 30)) = i
      cn = cn + 1
    End If

    If i Mod 2 = 0 Then
      GoTo owari
    End If

    r = Sqr(i)
    For j = 3 To r Step 2
      If i Mod j = 0 Then
        GoTo owari
      End If
    Next

    Cells(6 + Int(cn / 20), 2 + (cn Mod 20)) = i
    cn = cn + 1
owari:
  Next

  Cells(7 + Int(cn / 20), 2) = "素数個数"
  Cells(7 + Int(cn / 20), 3) = cn

End Sub


Private Sub CommandButton2_Click()

  Columns("B:AE").Select
  Selection.ClearContents
  Cells(1, 1).Select

End Sub

GoTo owariは行ラベルowariへ飛べという命令です。
BASICの頃、スパゲッティプログラムの元凶としてやり玉に挙げられたGoTo文ですが、
次の原則を守れば、使ってもよいと思います。
@ 飛ぶ箇所は一カ所のみ
A 必ず下へ飛ぶ


さて、前者と後者ではどちらがわかりやすいでしょうか。圧倒的に前者ではないでしょうか。後者は
  For i = 2 To n
    If i = 2 Then
      Cells(6 + Int(cn / 30), 2 + (cn Mod 30)) = i
      cn = cn + 1
    End If

    If i Mod 2 = 0 Then
      GoTo owari
    End If

    r = Sqr(i)
    For j = 3 To r Step 2
      If i Mod j = 0 Then
        GoTo owari
      End If
    Next

    Cells(6 + Int(cn / 20), 2 + (cn Mod 20)) = i
    cn = cn + 1
owari:
  Next
の部分が2次元ループになっています。
それに対して前者では、
  r = Sqr(n)
  For i = 3 To r Step 2
    If n Mod i = 0 Then
      Exit Sub
    End If
  Next
と1次元ループです。
理由は、Private Sub CommandButton1_Clickの部分でもう一つの次元
  For i = 2 To n
    f (i)
  Next
を受け持っているからです。
つまり、メインプロシジャとSubプロシージャで次元を分担して受け持っているわけです。
次元ごとに分担させれば、3次元や4次元であっても簡単にできます。
もし、4次元を1つのプロシージャに担当させるとすると、頭が混乱してしまいますが、
4つのプロシージャを用意すれば、すべてが1次元ですから、かなりすっきりします。
Funcitonプロシージャの終わりのところで、プロシージャを使用する意義をまとめるつもりですが、
意義の1つは次元を分割することによってわかりやすくなるという点です。

わかりにくい後者を持ち出した理由は、引数は複数指定できることを説明したかったからです。


今回は、後者を参考にして範囲は、1から終わりの数までではなく、
はじめも終わりも指定できるように改良したいと思います。
o001
o002
f (n)は、今回は2つの引数f(引数1,引数2)を持ちます。すると、プロシージャの宣言も
Sub f(引数1 As 型,引数2 As 型)とします。
例えば引数がhとoのときは、
次のようにしてプロシージャを呼び出します。
f h,o
です。
C言語などではf(h,o)すっきりした呼び出しになりますが、VBではこのような呼び出しは認めていません。
気持ちが悪いのですが、f h,oと書くしかありません。
尚、引数が1つときのf (n)は、f n でもよいのです。
私の好みは圧倒的にf(n)です。
ですから、f h,oもf(h,o)と書きたいのですがだめなのです。



第4話へ 第6話へ

004


vc++講義へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座へ
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ

数学研究室に戻る