【第10章】平均を求めるプログラム(2)選択処理


[回数が決まっていない繰り返し処理]

 不定回の繰り返し処理のやり方はおわかりいただけたでしょうか。回数が決まってないとはいえ、データの件数が無限ということはそうそうあることではありません。テストの平均点を求めるプログラムなら受験者の点数すべて入力し終わったらループは終了で、平均の計算に移ります。では、何人受験したかわからない学力テストの平均点を求めるプログラムではどうしたらよいでしょう。この場合、よく使われる方法は、「あり得ないデータ」が入ってきたところでループから抜けるというものです。この章ではさらに「条件によって処理内容を変える」という方法を学びます。コンピュータの最もコンピュータらしい部分で、これができるゆえに、筆者が小学生だった昭和40年頃は、コンピュータは「人工頭脳」と呼ばれたりしたものでした。今でも中国語では「電脳」といい、日本でも電脳少女など、ホビーの世界ではこの言い方が使われてますね。
 歳とると昔話が多くなってダメですね。話を元に戻します。たとえば

1)テストの点数は0点~100点の範囲である
2)点数に999が入力されたらデータ入力のループを抜ける
3)児童の出席番号(または受験番号)は1、2、3、・・・、Nとなっていて欠番はないものとする。

という前提で、不定回数の繰り返し処理によるテストの平均を求めるアルゴリズムを考えてみます。基本的な流れは次のようになります。


図10_1.受験者人数が一定でない学力テストの平均点を求める図10_1.受験者人数が一定でない学力テストの平均点を求める
図10_1.受験者人数が一定でない学力テストの平均点を求める

 上の図で、入力された点数が(たとえば)75のときと999のときでは処理の流れがどう変わるかを辿ってみてください。このアルゴリズムをTiny BASICでコーディング(プログラミング言語を使って実際にプログラムを作成すること)すると次のようになります。

         1: PRINT "***テストの平均点***"
         2: GOKEI=0
         3: NINZU=0
         4: BANGO=0
         5: TENSU=-1
         6: WHILE TENSU<>999
         7:   BANGO=BANGO+1
         8:   PRINT BANGO;"番";
         9:   INPUT "点数(999=END)",TENSU
       10:   IF TENSU<>999 THEN
       11:     GOKEI=GOKEI+TENSU
       12:     NINZU=NINZU+1
       13:   END IF
       14: WEND
       15: HEIKIN=GOKEI/NINZU
       16: PRINT "平均点は";HEIKIN
       17: END

      図10_3.受験者人数が一定でない学力テストの平均点を求めるプログラム

 1~3行目はもう説明不要ですね。
 4行目の変数BANGOは出席番号です。え?これ、NINZUを使えばいいんじゃない?と思われる方もいると思いますが、それはあまり感心しません。今ここでは番号の欠番はないものとしていますが、たとえば学校の場合、転校などによっていなくなった児童がいたりします。筆者の知る限りではこういうときその児童の出席番号は欠番となります(学年が変わってクラス替えがない限り1つずつ出席番号が前へずれるということはありません)。塾・予備校などの学力テストなら受験申し込みはしたものの受験はしなかったという児童・生徒がいるかもしれません。そういうとき、データ件数の値と出席番号(受験番号)の値が一致しなくなることは容易に想像がつきます。そのようなことにも対処できるようなプログラムにするにはデータ件数と出席番号は別々の変数にした方が後でプログラムの修正が楽になります。
 実際プロのプログラマが作ったプログラムを拝見すると後から機能の追加の要求がきたり、処理内容の一部に変更があってプログラムを修正(メンテナンス)する必要が出てきたときのことを想定して書かれていることがうかがえます。
 5行目はループに入るために、その条件となる変数TENSUに「得点の範囲外でループ終了条件とも違う値」を代入しています。WHILEの後ろの条件はループ実行条件であることを思い出してください。
 7~9行目、これで点数入力のループに入ったのですから出席番号を +1 して、点数入力です。
 10行目がこの章の主役、IF文です。ここでは「変数TENSUの値が999でないときはTHEN以下の処理をせよ」ということになります。どこまでかを示すのが13行目にあるEND IFです(詳細は次節で)。
 繰り返し処理はここまでなので14行目にはWENDがあり、6行目のループ実行判定に戻ります。もし今、入力した内容がループ終了条件の999だったら、11~12行目の処理は行なわずに6行目に戻ってくることになります。ここでTENSUの値は999ですから、ループ実行条件は成立せず(ループ終了条件が成立し)、15行目以下に飛びます。平均を計算し、表示してプログラムは終わります。


[IF ~ END制御文]

 このプログラム中に IF~END IFというのが出てきます。勘の良い方なら「ん?この構文は?FOR ~ NEXTやWHILE ~ WENDのように条件によってプログラムの実行順序を変える制御文かな?」と思ったことでしょう。その通りです。ただ、IF ~ END IFは繰り返し処理というより、条件によって処理内容が変わる選択処理に向いている制御文です。プログラミング言語によっては判断・分岐命令と呼ばれることもあります。
1)IF ~ END IF制御文の使い方の基本はこうなります。
  IF 条件式 THEN
    条件式が成立したときに実行される命令
  ELSE
    条件式が成立しなかったときに実行される命令
  END IF
ここで、条件が成立しなかった時に行なう処理が何もなければ、ELSE以下、END IFの手前までは省略できます(上のサンプルプログラムがそうです)。
2)さらに条件を細かく分けたいときには、このような使い方もできます。

  IF 条件式1 THEN
    条件式1が成立したときに実行される命令
  ELSEIF 条件式2 THEN
    条件式1が成立しないが、条件式2は成立したときに実行される命令
  ELSE
    条件式1も条件式2も成立しなかったときに実行される命令
  END IF

 これは少々わかりにくいと思いますので、実例でみてみましょう。図10-3のプログラムでは入力された値が1か2か、それ以外かによって、処理の内容が変わっています。


    PRINT "サービスデーのご案内"
    INPUT "お客様の性別は 1.男性 2.女性 3.無回答 ",SEI
    IF SEI=1 THEN
      PRINT "毎週火曜日は男性のお客様は¥1000で食べ放題"
    ELSEIF SEI=2 THEN
         PRINT "毎週木曜日は女性のお客様は¥1000で食べ放題"
    ELSE
    PRINT "毎週水曜日は¥1000で食べ放題"
    END IF
    PRINT
    PRINT "焼肉 〇〇"
    END


     図10_3.条件によって処理内容が選択されるプログラム

 入力内容が1か2か3かで処理の流れがどのようになるか(この例では画面に表示される内容)、考えてみてください。実行結果は図10-4のようになります。


図10-4.条件によって処理内容が選択される
図10-4.条件によって処理内容が選択される

 こんな焼肉屋さんがあったら、火・水曜日はいつもここで夕食ですなぁ(^ ^;
3)IF~END制御文も、FOR~NEXT制御文、WHILE~WEND制御文同様、ネスティングができます。

     1:SCORE=0
     2:PRINT "歴史クイズ"
     3:INPUT "日本最初の元号は 1.大和 2.大化 3.文化 ",ANS
     4:IF ANS=2 THEN
     5:    SCORE=SCORE+10
     6:    INPUT "徳川第八代将軍は 1.吉宗 2.家光 3.綱吉 ",ANS
     7:    IF ANS=1 THEN
     8:        SCORE=SCORE+10
     9:        INPUT "フランス革命の始まりとされているのは 1.ナポレオン台頭 2.ポーランド分割 3.バスティーユ監獄衝撃",ANS
    10:       IF ANS=3 THEN
    11:          SCORE=SCORE+10
    12:       ELSE
    13:          PRINT "正解は3.バスティーユ監獄襲撃です"
    14:       END IF
    15:   ELSE
    16:       PRINT "正解は1.吉宗です"
    17:   END IF
    18:ELSE
    19:    PRINT "正解は2.大化です"
    20:END IF
    21:PRINT "SCORE=";SCORE
    22:END

     図10-5.正解したら次へ進めるクイズのプログラム

 図10-5は1つでも正解できないと脱落するという(鬼畜な?)クイズゲームです。正解しないと次の問題に進めないというのはIF~ENDIFのネスティングで実現してます。1問目が正解なら5行目以下が実行され、不正解なら19行目へ飛んでプログラム終了です。しかし6~7行目に2問めと解答の判定があります。2問めも正解なら8行目以下が実行され、不正解なら16行目へ飛びます。ここで1問目は正解しているので18~20行目は無視して21行目へ飛び、プログラム終了です。同様に9~10行目に3問めと解答の判定があります。正解なら11行目を、不正解なら13行目を実行してプログラム終了です。

【Tiny BASICの文法(4)】マルチステートメント
 Tiny Basicでは1行に1ステートメントを書くのが普通ですが : (半角のコロン)を使って1行に2つ以上のステートメントを書くことができます(マルチステートメント)。たとえば
       T=0
       INPUT "Nの値は";N
       FOR I=1 TO N
       T=T+I
       NEXT I
       PRINT "1~";N;"の自然数の合計は";T
       END

のプログラムは次のように書いてもTiny Basicの文法としては間違いではありません。

T=0:INPUT "Nの値は";N:FOR I=1 TO N:T=T+I:NEXT I:PRINT "1~";N;"の自然数の合計は";T:END

 ただ、これは読みにくいことこの上ないですね。マルチステートメントはこのようにむやみに使うとプログラムがわかりにくくなる原因になります。昔のBASICはIF制御文はブロック化ができなかったので、このマルチステートメントは絶対必要だったのですが、今のTiny Basicでは必要ないものとなりました。マルチステートメントは使わないようにしましょう。

【昔はよかったなぁ】

 今回は「昔はよかった」ではなく「昔はひどかったなぁ」というお話です。
 図10-3のプログラムを昔のBASICで書くと図10-5のようになります。

図10-5.条件により処理内容が変わるプログラムを昔のBASICで書くと
図10-5.条件により処理内容が変わるプログラムを昔のBASICで書くと

 昔のBASICは END IF がありませんでした。つまりIFブロックは使えませんでした。入力内容により処理内容を変えたいなら行番号30のようにELSEIF(昔のBASICではELSE IF)以下を1ステートメントにしなければなりませんでした。
 また条件が成立した(反対に成立しなかった)時の処理が複数あるとき、それをすべて1ステートメントで書かなくてはならなかったので、図10-3のプログラムの10~13行目の部分を昔のBASICで書くと、
   IF TENSU<>999 THEN GOKEI=GOKEI+TENSU : NINZU=NINZU+1
となります。後でプログラムを見なおした時、自分で作ったプログラムなのに何が何だかわからないということもよくありました。今のTiny BasicはIF制御文もEND IFを使ってFOR制御文、WHILE制御文のようにブロック化し、わかりやすいプログラムが書けるようになりました。

【この章のまとめ】

条件によって処理内容が変わる処理を選択処理という。

Tiny BASICでは選択処理に向いている制御文はIF ~ END IF制御文である。基本的な書き方は

  IF 条件式 THEN
    条件式が成立したときの処理内容
  END IF

である。さらに条件を細かく分けたいときは
  IF 条件式1 THEN
    条件式1が成立したときの処理内容
  ELSEIF 条件式2 THEN
    条件式1は成立しないが、条件式2が成立したときの処理内容
  END IF

【演習6】ユーザー認証のプログラムを作ってみましょう。登録ユーザーは2人で、登録した名前で認証するものとします(ここでは変数で入れておくことにしておきます)。ユーザー名を入力し、登録ユーザー名のどちらかと一致すれば「〇〇(登録ユーザー名)さん、こんにちは」どちらとも一致しなければ「認証できませんでした」と表示するようにすること。このプログラムはいろいろな方法があるのですが、習熟のため、IF制御文を使うようにしましょう。

【ここまでのまとめ】

 ここまでで、プログラムの基本的な流れ「順次処理」「繰り返し処理」「選択処理」についてひととおりやってきました。コンピュータのプログラムはゲームのプログラムから銀行のシステム、人命を預かる新幹線の列車集中制御(CTC)のプログラムまで基本はこの3つの流れの組み合わせでできています。ここまでの内容がわかったら、ご自分のアイデアでプログラムを作ってみてください。そういう経験をたくさん積んでゆけば、プログラミング的思考とは何かがおのずとわかってくることでしょう。

【第9章】繰り返し処理(2)


[回数が決まっていない繰り返し]

第7~8章でやった繰り返し処理はループの回数が決まっていました(5回の例で説明しました)。これがもし回数が増えたらどうしましょうか。たとえばテストを受けた児童の人数が10人、20人・・・100人と増えたら?この場合は


                         FOR ループ変数=初期値 TO 終端値

の終端値を変えれば済むことです。では全国規模の模試のように受験者が何千人、何万人規模で、答案を回収するまで実際に受験した人数か試験が終わってわからないような場合はどうしたらよいでしょう。結論を先に言いますと、FOR ~ NEXT ループは不定回の繰り返し処理にはあまり向きません。では、図9-1のようなクイズのプログラムで、ある条件を満たしている間、繰り返し処理を行なう方法を考えてみます。


図9-1.不定回繰り返し
図9-1.不定回繰り返し


 図9-1の流れに従って作ったプログラムは図9-2のようになります。

            SEIKAI=1
            ANS=0
            WHILE ANS<>SEIKAI
                     PRINT "幻想即興曲、子犬のワルツで知られる作曲家といえば?"
                     PRINT "1. ショパン 2.ショクパン"
                     INPUT "番号で応えてください",ANS
            WEND
            END

                                                    図9-2.クイズのプログラム

 まず、3行目のWHILEなんちゃらと5行目のWENDから説明します。WHILEは「~の間」という意味ですね。何となく想像つくと思いますが、これは「~である間、以下の処理を繰り返せ」という意味です。「どこまでを」を指示しているのが WEND です。このWHILE ~ WENDもFOR ~ NEXTと同じくプログラムの実行順序をコントロールする制御文です。WHILEとWENDで囲まれた部分をWHILEブロックといいます。WHILEの後ろに来るのは繰り返し実行条件です。ここで<>というのは≠の意味です(比較演算子と呼ばれるもののひとつです)。つまりこの3行目は「変数ANS$の内容が変数SEIKAI$の内容と等しくない間,以下の処理を実行せよ」という意味になります。
 Tiny BASICだけでなくほとんどのプログラミング言語では≠が使えません。多くのBASICでは<>(または><)、サーバープログラム向きのperlでは!=、昔懐かしいFORTRANでは.NE.などとなっています。


図9-3.クイズのプログラム実行結果
図9-3.クイズのプログラム実行結果


 このプログラムを実行すると図9-3のようになります。問題文はWHILEブロック内のPRINTで表示、解答入力は同じくWHILEブロック内のINPUTで行ないます。これにより正解を答えられるまで問題文の表示と解答入力に戻り、正解が出るとWENDの次に進みます。答えの入力に繰り返す回数は決まっていません。正解するまで回数無制限のデスマッチです。このプログラムではWENDの次には何もありませんから、正解が出ればこれで実行終了です。このように繰り返し回数が決まっていないループでは FOR ~ NEXT制御文よりWHILE~WEND制御文の方が適していることがわかります。

[WHILE ~ WEND 制御文]

 WHILE文の書き方をまとめると次のようになります。
      WHILE 条件式
        繰り返して行う処理
      WEND

1)WHILEとWENDは必ず対になっていなくてはなりません。
2)WHILEブロックはプログラム中にいくつあってもかまいません。
3)WHILEブロックの中にWHILEブロックを包括することができます(ネスティング)。
WHILEブロックのネスティングを使うと、データの誤入力(誤ったデータを入力すること)防止を施すことができます(この後の章でやります)。

[繰り返し条件]


 WHILEの後ろに書かれる条件式は、繰り返し(ループ)に入るための条件です。繰り返し処理にWHILE ~ WEND を使う場合、繰り返しを終了する条件とは反対になります。
図9-2のプログラム例なら、入力内容が正解でなければループに入れ(終了条件からみれば、入力内容が正解だったらループを抜けよ)ということになります。プログラミングの際に注意を要するところです。筆者はプログラム初心者だった頃、これがよくわかっていなくて1本のプログラムのデバッグで徹夜したことがあります。

[条件式と比較演算子・論理演算子]

 条件式は繰り返し処理の他、条件によって処理内容を選ぶ選択処理でも出てくるものですから、ここで書き方と意味をしっかり覚えましょう。条件式の書き方は

        式1 比較演算子 式2

となります。式?と思われた方、プログラミングの世界では変数1個、数値1つ、ストリング1つでも式であることを思い出してください。条件式は2つの式を演算子で結んだ形で書かれます。このときに使われる演算子を比較演算子といいます。Tiny BASICで使える比較演算子は次の通りです(下の表では見やすくするためにすべて全角で書きましたが、実際にプログラム中で使うときには半角です)

図9-4.Tiny BASICで使用できる比較演算子
図9-4.Tiny BASICで使用できる比較演算子

 = はここまでずっと代入演算子として使われてきました。代入演算子としての = は「右辺の値を左辺に代入する」でしたから、左辺は変数1つに限定されました。A=5 のような書き方はOKですが、5=Aのような書き方はだめでした。条件式としての = は数学の等号と同じ意味なので、たとえば 5+3=A といった書き方ができます。
 このサンプルプログラムには出てきませんが、条件式を書くのにもうひとつ覚えておきたいのは論理演算子です。

図9-5.Tiny BASICで使用できる論理演算子
図9-5.Tiny BASICで使用できる論理演算子


 論理演算子はこの他にもいろいろあるのですが、図9-5の3つはぜひ使えるようにしておきたいというものです。論理演算子の優先順位は、NOT、AND、ORです。ただし( )内が優先されます。

               IF A=B AND (C=D OR NOT E=F) THEN
                   処理
               END IF

  これは
    E=Fが成立しない、またはC=Dが成立し、かつA=Bが成立するとき以下の処理を行なう
ということになります。

[この章のまとめ]

不定回の繰り返し処理では、WHILE ~ WEND制御文を使う。

WHILE文の書き方は

WHILE 繰り返し実行条件

繰り返し実行条件が成立する時は繰り返し終了条件は成立しない。繰り返し終了条件が成立するときは繰り返し実行条件は成立しない。

条件式の書き方は

         式1 比較演算子 式2

         条件式1 論理演算子 条件式2

比較演算子としての=は代入命令ではなく、数学の等号と同じ意味を持つ。

【演習5】

 WHILE ~ WEND制御文を使って、クイズの問題を作りなさい。答えはキーボードから番号で入力するものとします。問題文はPRINT命令で実行画面に表示/INPUT ストリングで入力窓に表示、どちらでもけっこうです。正解だったら「正解です」というメッセージと正解するまでにかかった回数を表示して終わるようにすること。問題が思いつかない人は下記の問題例を使ってください。( )内が正解です。
(問題例)
  ベートーヴェンの交響曲第5番は何と呼ばれていますか(1.英雄 2.運命 3.田園、正解は2)
  ポークは豚、ビーフは牛、チキンは鶏、ではターキーは(1.羊 2.アヒル 3.七面鳥、正解は3)
  明治5年、日本で最初に開通した鉄道は東京からどこまで(1.横浜 2.京都 3.大阪、正解は1) 


【第8章】平均を求めるプログラム(1)


 前章で覚えた FOR ~ NEXT制御文を使うと、入力したデータの合計や平均を求めるプログラムができます。この章からしばらくの間、テストの成績処理プログラム(学校のテストにはいい思い出がない方、少しの間がまんしてください)で合計、平均の求め方、ある条件により処理内容が変わる選択処理(次章以後)、変数の再利用以外のもっと高度なデータ再利用の方法を学びます。
 いよいよコンピュータならではのプログラミングに入ります。少しだけお楽しみに(^ ^;

[平均を求めるアルゴリズム]


 アルゴリズムとは、問題解決の手順です。コンピュータのプログラムの世界では、主として計算、代入、条件判断をどのように組み合わせ、どのように繰り返せば目的の仕事ができるか、ということになります。前章までのサンプル程度のプログラムならパソコンの前に座ってチャッチャと作れますが、もう少し長い(規模の大きい)プログラムになると、最初にアルゴリズムを考えてから作り出さないと後で出来上がったプログラムを見直した時、作った本人でさえ何が何だかわからない、グチャグチャなプログラム(プロのプログラマが「スパゲッティプログラム」と呼んでいるヤツです)になってしまうこともしばしばです。ということでここから後はサンプルプログラムをお見せする前に、どのように考えてこのプログラムになったか、というアルゴリズムを示してゆくことにします。


 5人の児童のテストの点数が次のようになっているとします。
   75、80、60、35、95
 この平均点を求めます。この程度の計算なら皆さんなら5つの数字をながめて暗算で 69 点とわかると思います。ところがコンピュータに、5つの数字を見せて「平均は?」と言ってもわからないのです。コンピュータでいくつかの数の平均を求めるなら、1つ1つのデータを加算し、データ件数を数え、全部のデータを加算し終わったら、その値を数えたデータ件数で割る、という何とものんびりとした作業を行うことになります。


図8_1.5人の児童のテストの平均を求めるアルゴリズム
図8-1.5人の児童のテストの平均を求めるアルゴリズム

 このアルゴリズムをコンピュータで実現するのがコンピュータのプログラムであり、Tiny BASIC for Windowsはそのためのツールのひとつということになります。ではサンプルプログラムです(図8-2)。サンプルプログラムの各行に行番号が付いていますが、これは説明用のためのもので、実際にプログラムを作るときには省略してください。以後サンプルプログラムが10行以上になるときにはこのようにします。

        1: PRINT "テストの平均点"
        2: GOKEI=0
        3: NINZU=0
        4: FOR I=1 TO 5
        5:   PRINT I;"番";
        6:   INPUT "点数",TENSU
        7:   GOKEI=GOKEI+TENSU
        8:   NINZU=NINZU+1
        9: NEXT I
       10: HEIKIN=GOKEI/NINZU
       11: PRINT "平均点は";HEIKIN
       12: END

         図8-2.平均を求めるプログラム

 ここでは第2章でやった代入演算子が活躍します(忘れてしまった方は第2章図2-5をもう一度見てください)。
 まず、5~8行目(ループの中)を見てください。
 5行目は「これから入力するのは何番目のデータか」ということを表示しています。誤操作(誤入力)防止のためのものだす。
 6行目でキーボードから点数を入力し、変数TENSUに代入します。
 7行目は今入力した点数を、変数GOKEIに加算しています。
 8行目では入力した件数をカウントしています(この場合、テストを受けた人数)このプログラムでは繰り返しが5回(人数は5人)と決まっているので、このようにデータ件数をカウントするのはあまり意味がありませんが、データ件数がループ変数の終端値と一致するとは限りません(後の章でそういう例が出てきます)。データ件数はループ変数に頼らず別の変数でカウントするようにしましょう。
 7、8行目の代入演算子=の使い方に着目してください。思い出しましたか。代入演算子の意味は「右辺の値を左辺に代入する」命令でしたね。
 この4行は点数の入力がすべて終わるまで繰り返しますから、4、9行目の FOR ~ NEXTで、(今回は)5回繰り返すようにしています。
 では、その他の箇所を見てみましょう。 
 1行目は「何のプログラムか」を表示しています。これはもちろん、誤操作(誤実行)防止策です。
 2行目、3行目はそれぞれ点数の合計、データ件数をカウントする変数ですが、これは処理に先立ち、0にしておく必要があります。なぜかというと、Tiny BASIC for Windowsを始め、多くのBASICではプログラム実行スタート時にすべての数値変数は0、ストリング変数は""(Null、何も入っていない)にリセットされるのですが、プログラミング言語はすべてそうなっているとは限りません。最初にクリアしておかないと何が入っているかわからないという言語もあります。筆者が30年ほど前に使っていたFORTRAN、COBOLなどではそうでした。また今日では、Visual BASICなどのように、最初に使用宣言をしていない変数は使えない、というプログラミング言語もあります。
 合計や平均を求めるプログラムでは、データの合計、データ数カウントのための変数は、最初に0にしておく(ゼロクリア)することを習慣にしましょう

図8-3.実行中(3番目のデータの入力待ち)
図8-3.実行中(3番目のデータの入力待ち)


 図8-3はこのプログラムの実行中です。入力窓は省略します。実行画面には、これから何番目のデータを入れるのかが表示されています。該当データを入れると何番目という表示(INPUT命令の直前のPRINT命令で表示した内容)が消えてしまいますが、これはTiny BASIC for Windowsの仕様なのでどうにもなりません。今後のバージョンアップで改善されることを期待しています。

図8-4.実行結果(平均が計算され表示された)
図8-4.実行結果(平均が計算され表示された)


 データをすべて入力すると平均が計算され表示されてプログラムを終わります(図8-4)

【この章のまとめ】

問題解決の手順のことをアルゴリズムという。

代入演算子=とFOR ~ NEXTループを組み合わせると、入力したデータの合計や平均を求めるプログラムができる。

データを加算する(合計)やデータ件数を数えるための変数は、ループに入る前にゼロクリアしておく

【第7章】繰り返し処理

[一定回数同じ処理を繰り返すプログラム]

 ここまでずっと順次処理ばかりやってきました。前にも言ったとおり、プログラムの最初から最後まで順番に命令を実行してゆく順次処理はコンピュータのプログラムの基本なのですが、これだけではコンピュータを使うメリットはあまり感じられません。電源が安定して供給され、故障や過熱による部品破損などがない限り疲れを知らないコンピュータらしい仕事といえば、同じ命令を何回も実行する繰り返し処理でしょう。
 図7-1のプログラムを実行してみてください。2、3行目のインデント(字下げ)はしなくても結果は変わりません。結果は図7-2.のようになります。

            FOR I=1 TO 5 
              PRINT "HELLO. Tiny BASIC"
              PRINT 3+5
            NEXT I
            END


             図7-1.同じことを繰り返すプログラム
 

図7-2.同じことをくり返した
図7-2.同じことをくり返した


 プログラム2行目にPRINT "HELLO. Tiny BASIC"とあり、3行目にPRINT 3+5とありますから、このプログラムは"HELLO. Tiny BASIC"というストリングと、3+5の計算結果を表示することはおわかりになると思いますが、実行結果を見るとこれが1セットで5セット(5回)表示されています。なぜこうなったのでしょうか。それは1行目の FOR I=1 TO 5 と4行目の NEXT が為せる業です。
 FORはこの場合、For You のForではなく、「~の間」と考えてください。 1行目は「変数 I の値が 1 から始まり 5 になるまでの間、以下を実行せよ」の意味になります。以下ってどこまで?ということになりますが、それを指示するのが4行目の NEXT です。「次」という意味ですが、NEXT ~で「次の~」ということになりますから、繰り返しはここまで、という指示と考えてください。このプログラムでは変数 I の値は繰り返しに突入する時に自動的に 1 とされ、NEXT I に来たところで、これまた自動的に +1 されます。このようにして 5 になって最後の回を実行して NEXT I に来たところで、 +1 されて 6 になります。これでFORに戻ると、すでに繰り返しの条件「 I が 5 になるまで」は満たしていますから、もう繰り返し部分には入らず、NEXT の次の行に移る、というわけです。
 この FOR ~ NEXT のように、プログラムの実行順序を変えたりするステートメントのことを制御文といいます(制御文はそれ自体、入力、処理、出力などは行なわず、プログラムの動作をコントロールするだけです)。筆者が知る限り、ほとんどのプログラミング言語で、この FOR ~ NEXT に相当する繰り返し制御文がありますので、これはぜひ使えるようになってください。

図7_3.FOR~NEXTによる繰り返し処理の流れ
図7-3.FOR~NEXTによる繰り返し処理の流れ



[FOR ~ NEXT制御文]
 FOR ~ NEXT制御文の書き方は次の通りです。

   FOR 変数=初期値 TO 終端値 STEP 増分

     繰り返し実行する命令
         |
         ↓
   NEXT 変数

1)FOR は必ず NEXT とペアでなくては使えません。
 FORとNEXTで囲まれた部分をFORブロックといいます。
 FOR文で使用する変数(上の例なら I )をループカウンタ(ループ変数)といいます。
2)両方の変数は同じで、かつ数値が入るもの(数値型変数)でなくてはなりません。NEXTの後ろの変数名は省略できますが、その場合、そこから前の方にさかのぼっていちばん近い FOR とペアだとみなされます。

3)FOR 変数=初期値 TO 終端値 STEP 増分は、「変数の値が初期値から始まって増分値ずつ変化し終端値に達するまでの間」の意味になります。増分は省略できます。省略した場合は +1とみなされます。したがって、図7-4のプログラムは図7_1.と同じ結果になります。

            FOR I=38 TO 42
               PRINT "HELLO. Tiny BASIC"
               PRINT 3+5
            NEXT I
            END

               図7-4.初期値、終端値

 初期値>終端値で増分を負の数にすることもできます。実行結果は図7_2のとおりです。

             FOR I=5 TO 1 STEP -1
             PRINT "発射";I;"秒前"
             NEXT I
             PRINT "発射!---→"
             END

図7_5.FOR~NEXTによる繰り返し処理の流れ
図7_5.増分値を負の数にした例(ロケット発射)

4)FORブロックはプログラム中にいくつあってもかまいません。次のプログラムでは、5~7行目10~12行目の2箇所にFORブロックがあります、実行結果は図7-4のとおりです。

      INPUT "お名前は";NAMAE$
      INPUT "1~10000の自然数を入力してください",N
      T=0

      FOR I=1 TO 5
        PRINT "Hello,";NAMAE$;"さん"
      NEXT I

      PRINT

      FOR I=1 TO N
        T=T+I
      NEXT I


      PRINT "1から";N;"までの自然数の和は";T

      END

図7_6.FORブロックが複数あるプログラム
図7_6.FORブロックが複数あるプログラムの実行結果

5)FORブロックの中にFORブロックを含むことができます。これをネスティング(入れ子)といいます。次のプログラムを実行すると結果は図7-5のようになります(掛け算九九です)。

      PRINT "掛け算九九表"
      PRINT " | 1 2 3 4 5 6 7 8 9"
      PRINT "--+------------------------------------"
      FOR I=1 TO 9
        PRINT I;"|";
        FOR J=1 TO 9
          A=I*J
          PRINT USING " ## ";A;
        NEXT J
        PRINT
      NEXT I
      END

図7_7.ネスティングのあるプログラム
図7_7.ネスティングのあるプログラムの実行結果

 ネスティングでは子ブロックは完全に親ブロックの中に包括されている必要があります。次の例だと左はOKですが、右はダメです。

   FOR I = 0 TO 10           FOR I=0 TO 20

     FOR J = 0 TO 10           FOR J = 0 TO 10

     NEXT J             NEXT I 

    NEXT I                 NEXT J

[ループカウンタ取り扱い上の注意]

 ループ変数はそのブロックの中で参照(ループ変数の中味を見たり、計算式の右辺に使用すること)することはできます。しかし、ループ変数自体に何かを代入すると思わぬ事態になることがあります。

 たとえば次のプログラムを実行するとどうなるでしょう。

      FOR I=10 TO 15
        PRINT "ピーターパンは";I;"歳になりました"
        I=10
      NEXT I
      END

      図7-8.ループカウンタの値をブロック内で変更すると

 FOR~NEXTループに入ったところで I の値は10です。次のPRINT命令は"ピーターパンは";I;"歳になりました"となっています。 の現在の値は10ですから、"ピーターパンは10歳になりました"と表示されます。3行目でループ変数である I に10を代入しているので、4行目のNEXT Iでは I の値は 11 になります。FORに戻ったところで I はまだ終端値になっていないので次はピーターパンは 11 歳になりました"と表示されます。次は 12 歳になるところですが、3行目の I=10 があるため、ここを繰り返し通る度に I は10に戻ってしまい、NEXT I まで来てもループ変数は再び 11 になります。その結果、このプログラムはピーターパンが 11 歳になったところで永遠に終わらない永久ループになります。「ピーターパンは永遠に歳をとらない男の子なんだからこれでいい」ではなくて、これはプログラムのミスでコンピュータが暴走しているのですから、プログラムを強制的に終了させなくてはなりません。「よし、バッテリーパックを外そう」、ダ、ダ、ダメですよぉ(冷汗)。稼働中のコンピュータの電源部に手を触れるなど危険きわまりない!

図7-9.永久ループしたプログラムの強制終了
図7-9.永久ループしたプログラムの強制終了

 実行中のプログラムを強制終了するには、実行画面上布施にある中断をクリックします(図7-6)。実行が停止し、実行画面にはOKの表示が出ます。
 このようにループ変数に何かを直接代入するとプログラムの暴走につながるバグ(bug=虫、プログラム中のミスのこと)を招きかねません。そして筆者の経験で言えば、この手のバグを探すのはかなり大変です(1坪ほどの地面からダンゴ虫を見つけるのと同じくらい)。ループ変数はその内容を使う(参照といいます)のはかまいませんがループ変数そのものの値を変えるのはやめておきしょう

[PRINT USING "~"]書式を指定して表示

 PRINT命令は続くオペランドの内容を表示するもので、手軽に使えて便利なのですが、数値もストリングもすべて左詰めで表示します。ストリングはそれでいいとしても数値は帳簿等に書く時も普通は右詰めで書きます。小数点以下を含む数値なら小数点の位置を合わせて書きます。PRINT命令でもこのように表示させるのが図7-7のプログラムに出てくるPRINT USING命令(書式指定)です。USINGの後ろの" "の部分には書式設定子が入ります。書式設定子にはいろいろなものがあるのですが、現時点では数値の書式設定だけ覚えておきましょう。
 数値の書式設定子には、#、.、,、\(すべて半角)があります。
   # は数字を表示する位置を指定します
   . は小数点の位置を指定します
   , はカンマの位置を指定します
\ を先頭につけると最上位桁の前に \ マークを付けます

 次のプログラムを実行すると結果は図7-10のようになります。

        A=1234500
        B=12345
        C=123.45
        D=12.345
        PRINT USING "##,###,###";A
        PRINT USING "##,###,###";B
        PRINT
        PRINT USING "###.##";C
        PRINT USING "###.##";D
        PRINT
        PRINT D
        END

図7-10.書式設定のサンプル
図7-10.書式設定のサンプル

[この章のまとめ]

 プログラムの全体または一部を何回も繰り返し実行することを繰り返し処理(またはループ)という。

 計算や代入、表示ではなく、プログラムの動きをコントロールする分を制御文という。

 Tiny BASICでは FOR ~ NEXT制御文を使うことによって繰り返し処理(ループ)が実現できる。使い方は

  FOR ループ変数=初期値 TO 終端値 STEP 増分

    繰り返し実行する命令

  NEXT ループ変数

ループ変数の内容を繰り返し処理の中で参照するのはよいが、ループ変数そのものの値を変えるようなことは避けた方がよい。

FORブロックは1つのプログラムの中にいくつあってもよい。

fORブロックの中にFORブロックを含めることができる(ネスティング)。

PRINT USINGは書式を設定して画面表示する命令である。

【演習4】FOR ~ NEXT制御文を使って、1 から15までの自然数のうち、奇数( 2 で割り切れない数)を表示するプログラムを作りなさい。また 3 から15までの自然数のうち 3 の倍数を表示するプログラムはどうなるでしょう。

【第6章】誤操作を防ぐ工夫
図6-1.台形
図6-1.台形

 さて、前章で学んだストリングやPRINT命令の様々な使い方を活用して、台形の面積を求めるプログラムを作ってみましょう。ここではオペレータの誤操作をできるだけ防ぐ工夫についてもお話します。
 台形の面積は、上底をa、下底をb、高さをhとしたとき、
                    (a+b)×h÷2
で求められました。プログラムは次のようになりますね。

                INPUT A
                INPUT B
                INPUT H
                S=(A+B)*H/2
                PRINT S
                END

図6_2.実行結果
図6-2.実行結果
 

[できる限り誤操作対策をしよう]

 このプログラムを実行すると図6-2のようになります。プログラム中にINPUT命令が3回でてきますから、実行すると図のような入力ボックスが3回現れます。INPUT命令が多いと、それだけ現れる入力ボックスも多くなり、オペレータがそのプログラムを作った当人なら別として、そうではないときは「今ここで何のデータを入力するのか」がわかりにくくなります。また、実行画面も何が何だかわからなくなってきます。それは誤操作を招きやすくなるということでもあります。筆者の経験で言うと、コンピュータから個人情報などが漏洩するトラブル、システム全体をダウンさせたなどの原因の半分以上は誤操作によるものです。そして「操作がわかりにくい」「画面が見づらい」は誤操作を招く最大要因です。
 このプログラムを次のように改造して実行しましょう。

                  PRINT "台形の面積を求める"
                  INPUT "上底=";A
                  INPUT "下底=";B
                  INPUT "高さ=";H
                  S=(A+B)*H/2
                  PRINT
                  PRINT "面積=";S
                  END

 1行目ではこのプログラムが何のプログラムかを画面に表示しています。これを表示することにより、今ここで実行してよいプログラムかどうかオペレータに確認させるようにします。ここの実習ではそんな危険なプログラムは扱いませんが、実際のシステムでは、今ここで実行してはいけないプログラムを誤実行(誤操作の最も酷いもの)してシステムダウンを引き起こした、などというケースもあるからです。LINEなどのSNSでは送信相手の名前が画面上に表示されるようになっていますが、あれも誤操作・誤実行防止のためです。「今から帰る、愛してるよ、chu」と奥様に送るのを間違えて学生のグループに送信してしまったら?・・・明日からどのツラ下げて出勤するんだ!ということになります。
 プログラムの始めに「何のプログラムか」を表示させるようにする、これも習慣づけておきましょう。
 2行目のINPUT命令が実行されると、キーボードからの入力待ちになりますが、このとき入力ボックスと実行画面の両方に INPUT の後ろのストリングがそのまま表示されていることを確認してください(図6-3)。

図6-3.上底を入れるところ
図6-3.上底を入れるところ

 上底の値(この例は10)と入れてOKをクリックするとプログラムは先に進み、次は3行目のINPUT命令で下底の入力待ちになります(図6-4)。
図6-3.上底を入れるところ
図6-4.下底を入れるところ

 下底の値(この例は15)と入れてOKをクリックするとプログラムはさらに先に進み、次は4行目のINPUT命令で高さの入力待ちになります(図6-5)。

図6-5.高さを入れるところ
図6-5.高さを入れるところ

 高さの値(この例は4)を入れてOKをクリックするとプログラムは5行目に進み、ここまでで入れた上底、下底、高さをもとに台形の面積を計算します。
 そして最後に7行目で計算結果をディスプレイに表示します(図6-6)
図6-6.計算結果が表示された
図6-6.計算結果が表示された

 このようにキーボードからの入力待ちのところで、何のデータを入れるのかを表示することで、操作がわかりやすくなり、誤操作防止になります

[INPUT命令の便利な使い方]

Tiny BASICのINPUT命令は、次のような書き方ができます。

INPUT ストリング , 変数名
INPUT ストリング ; 変数名

 ストリングと変数名の区切りには , と ; が使えます。 , の場合はストリングが表示されるだけですが(図6-7)、 ; にするとストリングの後ろに?マークが付加されます(図6-8)。

図6_7.INPUT ストリング , 変数の場合
図6-7.INPUT ストリング , 変数の場合

図6_8.INPUT ストリング ; 変数の場合
図6-8.INPUT ストリング ; 変数の場合


[入力→処理→出力]

 コンピュータに何らかのデータを入れることを入力といい、コンピュータで処理した結果をディスプレイに表示したりプリンタで印字することを出力といいます。今後は当カテゴリーでもこの言い方をすることにします。

図6_9.コンピュータのプログラムの基本は入力→処理→出力
図6-9.コンピュータのプログラムの基本は入力→処理→出力


 そしてコンピュータのプログラムは、銀行のシステムのような巨大なものから、ゲームのようなホビープログラム、ここでのサンプルに出てくる小規模なものまですべて、入力→処理→出力という流れが基本になります。この章のサンプルプログラムなら、INPUT命令で上底、下底、高さを読み込む所が入力、台形の面積を計算する所が処理、計算した結果をPRINT命令で表示する所が出力です。

【Tiny BASICの文法(3)】プログラム中の空行

 プログラム中に空行(なにも書かれていない行)を入れることができます。空行は何行入れてもかまいません。たとえば
                  PRINT "台形の面積を求める"

                  INPUT "上底=";A
                  INPUT "下底=";B
                  INPUT "高さ=";H

                  S=(A+B)*H/2

                  PRINT
                  PRINT "面積=";S

                  END

のようにすると、一連の処理のかたまりがわかりやすくなります。プログラム中に空行を置いても、実行画面上で空行ができるわけではありません。実行画面上で行を空けたいときは
        PRINT
を使う必要があります。

【昔はよかったなぁ】

 この章でやったプログラムを昔のBASICでやると図6-10のようになります。

図6-10.台形の面積を求めるプログラムを昔のBASICで書くと
図6-10.台形の面積を求めるプログラムを昔のBASICで書くと

 昔のBASICではINPUT命令での入力待ちでも入力窓が出ません。プログラム作成・編集・実行すべて同一画面です。どちらがいいかは好みによります。
 昔のBASICではプログラム中に空行は入れられません。

【この章のまとめ】

 操作がわかりにくい、画面が見づらい、は誤操作を招く最大要因である。

 プログラム中には、誤操作・誤実行防止の対策を施しておくことがのぞましい。

 INPUT命令は INPUT ストリング,(または ; )変数、という使い方ができる

 コンピュータに何かのデータを入れることを入力、処理した結果を表示(印字)することを出力という

 コンピュータによるデータ処理の基本は入力→処理→出力という流れである

【演習3】直方体の底面積と体積を求めるプログラムを作りなさい。底面のたてとよこ、立体の高さはキーボードから入力するものとします。ただし画面の見やすさを工夫し、誤操作・誤実行対策を施すこと

- CafeLog -