前のページ|次のページ

プログラミングの基礎2



反復処理

同様の処理を何回も繰り返し実行させるプログラムの書き方.

反復処理1:For 〜 Next

繰り返す回数が決まっている場合に使用される記述の仕方.

構造

処理した回数を数える「カウンタ変数」を用意し,カウンタ変数の最初の値「初期値」と終了する値「終値」,数え方「増分(変化量)」を設定してカウントしながら処理を実行します.増分を負の値にして減らしながらカウントすることも可能です.また,増分が1の場合には Step の部分を省略できます.

For カウンタ変数 = 初期値 To 終値 Step 増分

  処理

Next カウンタ変数
          

例1

2つの数値を入力し,片方には2を足し,もう片方は2を掛ける作業を10回繰り返し,さらにそれぞれの初期値から10回計算した後までの和を求めるプログラムを作ります.出力は,繰り返しの回数とその時の数値を表示し,最後に和を出力させます.A1セルに回数の文字が入力されているとします.また,セルの位置を指定するために数値を使用したいので,セルの操作に Range ではなく Cells を使用しています.

回数 数値1 数値2
0 (ここに初期数値を入力) (ここに初期数値を入力)
Sub kyusu_wa()

  '変数宣言
  Dim i As Integer, n As Integer, m As Integer    '各回の値を表す
  Dim sum1 As Integer, sum2 As Integer    '和を計算する
              
    '入力された数値を代入
    n = Cells(2,2).Value
    m = Cells(2,3).Value

    '和の初期値を設定
    sum1 = n
    sum2 = m
              
    '反復処理;For文
    For i = 1 To 10
              
      '計算
      n = n + 2
      m = m * 2

      '和の計算
      sum1 = sum1 + n
      sum2 = sum2 + m
    
      '各回の結果をセルに表示
      Cells(2+i,1).Value = i
      Cells(2+i,2).Value = n
      Cells(2+i,3).Value = m
              
    Next i

    '和を表示
    Cells(i+3,1).Value = "合計"
    Cells(i+3,2).Value = sum1
    Cells(i+3,3).Value = sum2

End Sub
          

例2:多重ループ

For ~ Next を入れ子にして使用することで2重,3重の繰り返しを記述できます.

ここでは1から40までの掛け算の表を作成するプログラムを作ってみます.出力は新しいワークシートを作成してそこに表示します.

Sub kakezan()

  '変数宣言
  Dim i As Integer, j As Integer
  Dim mySheet As Worksheet

    'ワークシートオブジェクトの設定(右側に「掛算表」という名前で追加)
    set mySheet = Worksheets.Add(After:=Worksheets(3))
    mySheet.Name = "掛算表"
                          
    '反復処理;For文
    For i = 1 To 40
  
      For j = 1 To 40

        '各回の結果をセルに表示
          mySheet.Cells(i,j).Value = i*j
                          
      Next j
  
    Next i

End Sub
            

練習問題4-1

Excelのブックに新しいシートを追加し,VBEで新しい標準モジュールを挿入します.プロジェクトエクスプローラーに Sheet3 と Module3 が表示されるはずです.

Module3 のコードウィンドウに新しい Sub プロシージャを作成します.

次の a, b, c のどれかを1つ以上作成して下さい. Sub プロシージャ名は「ex_041a」または 「ex_041b」または 「ex_041c」にします.

練習問題4-1a

セルに初項と公差を入力し,等差数列の10項目までを表示するプログラムを作りましょう.結果は初項を入力したセルの下のセルに表示するようにし,使用するセルはこのプログラムを登録するボタンの下に来る位置のセルにしてください.Sheet3にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_041aに変えて下さい,ボタンはシートの左上あたりに配置してください.

練習問題4-1b

セルに初項と公比を入力し,等比数列の10項目までの和を計算して表示するプログラムを作りましょう.結果は初項を入力したセルの下のセルに表示するようにし,使用するセルはこのプログラムを登録するボタンの下に来る位置のセルにしてください.Sheet3にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_041bに変えて下さい,ボタンはシートの左上あたりに配置してください.

注意:整数型(Integer)は 32767 までの整数しか扱えないので,数列の和がそれを超えるような場合はエラーになってしまいます.これを回避する為には,変数の型を「Long(長整数型)」に変更します.

練習問題4-1c

セルに積分範囲の始点と終点,分割数を入力し,\(f(x) = \mathrm{e}^{-x^2}\) の定積分を求めるプログラムを作りましょう.結果は範囲を入力したセルの下のセルに表示するようにし,使用するセルはこのプログラムを登録するボタンの下に来る位置のセルにしてください.Sheet3にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_041cに変えて下さい,ボタンはシートの左上あたりに配置してください.

関数の定積分はある範囲で関数のグラフの面積を求めることです.これをコンピューター上で実現するには,関数の変数の範囲を細かく分割し,その分割幅と各分割点での関数の値を高さとした長方形の集合に面積の合計を計算することによって定積分の近似値とします.分割数を大きくする程正確な値に近くなります.正確な計算では,\(\int_{-\infty}^{\infty}\mathrm{e}^{-x^2}dx = \sqrt{\pi}\).

解説

\(x\)軸と\(ab\)間の函数\(f(x)\)のグラフに囲まれた面積は,\(n\)を分割数とすると, \( x_i = a + i \Delta x \)(\(\Delta x\)は\(x\)の分割幅)として次のように計算できる(これが関数の定積分の定義). \[ \int_a^b f(x)dx = \lim_{ \begin{smallmatrix} n \rightarrow \infty\\ (\Delta x \rightarrow 0) \end{smallmatrix} }\sum_{i=0}^{n-1}f(x_i)\Delta x, \quad x_0 = a, x_n = b \] ここで,\(x\)の分割幅\(\Delta x\)は次のように表せる. \[ \Delta x = \frac{b - a}{n} \]

ここで,\(f(x_i)\Delta x\)は,\(x_i\) における横 \(\Delta x\),縦 \(f(x_i)\),の細長い長方形の面積(図の黄色い長方形)を表し,これらを\(a\)から\(b\)まで足し合わせて行けば図形の面積の近似値になり,この極限値が面積に一致する.

Δ x f(x_i) x_i a b x f(x)

以上のことから,プログラムでは,\(ab\)間を\(n\)等分して,分割したそれぞれの位置での長方形の面積を求め,それらの和をとることで図形の面積の近似値を計算する.

\(i\) 個目の長方形の面積は, \[ \Delta S_i = f(x_i)\Delta x \] したがって,面積 \(S\) の近似値は,全ての長方形の面積を足し合わせて, \[ S = \Delta S_0 + \Delta S_1 + \Delta S_2 + \cdots + \Delta S_{n-1} = \sum_{i=0}^{n-1} \Delta S_i \] となる.


反復処理2:For Each 〜 Next

カウンタ変数を使用する代わりに,条件を満たすオブジェクト全てについて自動的に処理を実行します.

構造

Excelのブックは「Workbook」オブジェクトで,存在するブック全体は「Workbooks」コレクションです.同様に,Excelのシートは「Worksheet」オブジェクト,シート全体は「Worksheets」コレクション,Excelの各セルは「Range」オブジェクトでセルの範囲は「Range」コレクションとなります.

For Each オブジェクト変数 In コレクション
  処理
Next オブジェクト変数
          

A1セルに数値を入力し,上記の例の「掛算表」の中で入力した数値の倍数のセルの色を変えるプログラムを作ってみます.

Sub cell_color()

  Dim myRange As Range
  Dim n As Integer

  n = Range("A1").Value

  For Each myRange In Worksheets("掛算表").Range("B2:AO41")

    If myRange.Value Mod n = 0 Then myRange.Interior.Color = 65535

  Next

End Sub
          

反復処理3:Do Until 〜 Loop; Do 〜 Loop Until

条件を設定し,条件式が満たされるまで処理を繰り返すプログラムの書き方です.条件式を判定するタイミングによって2通りの記述の仕方があります.

構造1:Do Until 〜 Loop

最初に条件式を判定してから処理を実行します.従って,1回も処理を実行しないこともあります.

Do Until 条件式
  処理
Loop
          

セルに数値を入力し,フィボナッチ数列の値が入力した数値を超えた時の項数と値を表示する.

フィボナッチ数列とは,\(i\)項目の値を\(F_i\)と書いたとき,最初の2項の値を \(F_0 = 0\),\(F_1 = 1\) として次のようにして得られる数列です. \[ F_{i+2} = F_i + F_{i+1} \]

条件 項数
(ここに入力)
Sub fibonacci()
              
  Dim f0 As Integer, f1 As Integer, f2 As Integer
  Dim i As Integer, n As Integer
              
    n = Range("A2").Value
    i = 0
    f0 = 0
    f1 = 1
    f2 = 0
              
    Do Until f2 > n
                  
      f2 = f0 + f1
              
      f0 = f1
      f1 = f2
      
      i = i + 1
              
    Loop
            
    Range("B2").Value = i
    Range("C2").Value = f2
              
End Sub
            

構造2:Do 〜 Loop Until

処理を実行してから条件式を判定します.従って,少なくとも1回は処理を実行します.

Do
  処理
Loop Until 条件式
          

セルに年利を入力し,複利計算で元利合計が元金の2倍になる期間を求める

複利とは,次の期間の利息を元金と前期間の利息の合計に対して利率をかけて計算する方式です.

利率%(年利) 元金 合計 期間(年)
(ここに入力) (ここに入力)
Sub fukuri()
          
  Dim kikan As Integer
  Dim gankin As Long, risoku As Long, gokei As Long
  Dim nenri As Single
            
    nenri = Range("A2").Value
    gankin = Range("B2").Value
    kikan = 0
    risoku = 0
    gokei = gankin
            
    Do
          
      risoku = gokei * riritu / 100
      gokei = gokei + risoku
            
      kikan = kikan + 1
             
    Loop Until gokei > 2 * gankin
            
    Range("C2").Value = gokei
    Range("D2").Value = kikan
            
End Sub
                      

練習問題4-2

「ex_041x」の下に新しい Sub プロシージャ「ex_042a」または 「ex_042b」または 「ex_042c」を作成します.

練習問題4-2a

セルに正の係数 a, b の値と精度を入力し,方程式 \[ - ax + b = 0 \] の解を求めるプログラムを作りましょう.結果は係数を入力したセルの下のセルに表示するようにし,使用するセルはこのプログラムを登録するボタンの下に来る位置のセルにしてください.Sheet3にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_042aに変えて下さい,ボタンはex_041xのボタンの横に適当な間隔を開けて配置してください.

方程式の解は,\( y = -ax+b \) を計算したときに,\(y\) が0になる \(x\) です.単純なプログラムでは人間のように式変形によって解を求めることはできません.したがって,プログラムでは,\(y\) の値が最も0に近くなる \(x\) を探す方法を取ります.
具体的には,\(x\)の初期値を(例えば0に)設定し,式に代入して\(y\)の値を計算し,それが0より大きければ \(x\) を精度の値だけ増やして再度 \(y\) の値を計算するという作業を繰り返し実行するようにして,\(y\) の値が負になったときの \(x\) の値が方程式の解の近似値であると考えます.

Δ x(seido) x_i x(solution) x y

練習問題4-2b

セルに精度を入力し,連立方程式 \[ \left\{ \begin{array}{l} 3x + y = 1 \\ x - 2y = 5 \end{array} \right. \] の解を求めるプログラムを作りましょう.結果は精度を入力したセルの下のセルに表示するようにし,使用するセルはこのプログラムを登録するボタンの下に来る位置のセルにしてください.Sheet3にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_042bに変えて下さい,ボタンはex_041xのボタンの横に適当な間隔を開けて配置してください.

解説

連立方程式 \[ \left\{ \begin{array}{l} y = f_1(x) \\ y = f_2(x) \end{array} \right. \] の解は,2つの函数の交点として求められる.

2つの方程式の交点の近似値は,函数\(y_1 = f_1(x_1)\)と函数\(y_2 = f_2(x_2)\)の\(x_1 = x_2\)における\(y_1\)と\(y_2\)の差の絶対値が精度以下になるという条件で求められるので,プログラムでは,\(x\)の初期値と精度を設定して\(|y_2-y_1| = |f_2(x)-f_1(x)|\)の演算を\(x\)の値を変えながら精度の条件を満たすまで繰り返し実行し,結果として連立方程式の解の近似値を求める.このとき\(x\)の値は精度の10分の1位ずつ変えていきましょう.そうしないと,精度の値によっては\(|f_2(x)-f_1(x)|\)が精度の範囲に収まらない場合が生じ,繰り返しが終わらなくなることがあります.

注意:\(x\)の初期値に気をつける.例えば,\(x\)の値を増やしながら解を探す場合,初期値を解より大きい値にしてしまうと無限ループ(終わらないプログラム)になってしまいます.この問題では\(x = 0\)を初期値に取れば大丈夫です.

オプション:もし,どんな初期値を入力しても良いプログラムにしたければ,\(y\)の差の絶対値が減少する方向に\(x\)を変化させる(増やして探すか減らして探すかを場合分けする)ようなプログラムにしてみましょう.

練習問題4-2c

セルに係数 a, b, c, d, e と精度を入力し,連立方程式 \[ \left\{ \begin{array}{l} y = ax^2 + bx + c \\ y = dx + e \end{array} \right. \] の解を求めるプログラムを作りましょう.結果は精度を入力したセルの下のセルに表示するようにし,使用するセルはこのプログラムを登録するボタンの下に来る位置のセルにしてください.Sheet3にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_042cに変えて下さい,ボタンはex_041xのボタンの横に適当な間隔を開けて配置してください.

注意:係数の設定によっては解がない場合があり,無限ループ(終わらないプログラム)になってしまいます.係数の設定に気をつけましょう.

ヒント:解は2つあります.初期値を2次方程式の頂点から始めれば,増加,減少の各方向に変化させて探せば見つかるはずです.


反復処理4:Do While 〜 Loop ; Do 〜 Loop While

条件を設定し,条件式が満たされている間は処理を繰り返すプログラムの書き方です.条件式を判定するタイミングによって2通りの記述の仕方があります.

構造1:Do While 〜 Loop

最初に条件式を判定してから処理を実行します.従って,1回も処理を実行しないこともあります.

Do While 条件式
  処理
Loop
          

構造2:Do 〜 Loop While

処理を実行してから条件式を判定します.従って,少なくとも1回は処理を実行します.

Do 
  処理
Loop While 条件式
          

基本的には Until の場合と同じで,条件の設定が逆になるだけです.したがって,具体的な例は示しませんので,自分で Until の例を While に書き直してみましょう.


反復処理5:Exit For ; Exit Do

Exit For:For 〜 Next の繰り返しの中で,If文と合わせて使用し,条件を満たした場合は処理を定められた回数繰り返さずに直ちにループを抜けます.
Exit Do:繰り返しの条件を設定しない Do ~ Loop の繰り返しにおいて,If文と合わせて使用し,条件を満たした場合は直ちにループを抜けます.

構造

For 
  処理
  If 条件式 Then Exit For
Next
                      
Do 
  処理
  If 条件式 Then Exit Do 
Loop
          

入力した整数 n が素数かどうかを判定するプログラムを考えてみます.2 から始めて √n までの数で割り切れるかどうかを判定します.繰り返しは割り切れたところで終了して結果を表示します.

Sub sosu_hantei()

  Dim n As Integer
  Dim i As Integer
  Dim hantei As Boolean

    n = Range("A1").Value

    hantei = True

    For i = 2 To Sqr(n)

      If n Mod i = 0 Then

        hantei = False

        Exit For

      End If
        
    Next i

    If hantei Then

      Range("B1").Value = "素数です"

    Else

      Range("B1").Value = "素数ではありません"

    End If

End Sub
          

練習問題4-3(オプション)

「ex_042x」の下に新しい Sub プロシージャ「ex_043」を作成します.

セルに数値を入力し,入力した数値以下の最大の素数を求めるプログラムを作りましょう.結果は数値を入力したセルの下のセルに表示するようにし,使用するセルはこのプログラムを登録するボタンの下に来る位置のセルにしてください.Sheet3にフォームコントロールのボタンを挿入し,プログラムを登録して名前をex_043に変えて下さい,ボタンはex_042xのボタンの横に適当な間隔を開けて配置してください.