−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
   応用数学II                         1995.10.27/28
   12.プロシージャという概念(1)SUB文          飯島
               −配列という概念−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

12−1 配列

 実は,今までも配列という概念は使ってきている。言及しなかっただけのことだ。まず は,次のプログラムを入力し,実行してみよう。 CLS DIM x(100)                 ← 配列を定義している。 FOR i = 1 TO 100   x(i) = RND NEXT FOR i = 1 TO 100   PRINT x(i); NEXT PRINT max = 0 FOR i = 1 TO 100   IF x(i) > max THEN max = x(i) NEXT PRINT "max = "; max  そう,ここでは,「最大値」を求めています。このプログラムの最大の利点は,データ が100 個あっても,FOR ... NEXT によって,数行で済ませてしまうことができる点にあ ります。このように,         決まりきった作業を,複数のデータに行いたい場合 には,配列を定義し,                  ... x(i) ... というように「変数」を使って記述することができると便利なわけで,そういう目的で, 「配列」という概念があり,また実装されているわけです。

12−2 配列の大きさ

 さて,上では,100個のデータを処理していましたが,試しに,200個に修正して みましょう。上記のプログラムのどこを直したらいいですか。  そう,面倒くさくないとも言えますが,でも,やっぱり後で何回も修正する可能性があ るときは,いやなものです。特に,プログラミングしているときは,それぞれの定数とい うのは,その意味が分かっているのだけれど,後になってみると,一体それはどういう意 味だったのかが分からなくなったりして,間違いのもとになることが多いので,できるだ けその意味が分かるようにする必要があります。つまり,標語的に言うと,            「数値のまま残すのはトラブルのもと」 とでもいいましょうか。そこであらたしく「定義」するときだけにしたいものです。たと えば,上のプログラムの場合は, CLS DIM x(100) FOR i = 1 TO 100   x(i) = RND NEXT FOR i = 1 TO 100   PRINT x(i); NEXT PRINT max = 0 FOR i = 1 TO 100   IF x(i) > max THEN max = x(i) NEXT PRINT "max = "; max この下線部の部分は,それぞれ、「配列xの大きさ」という意味ですよね。そのため,2 00に変更するためには,これを全部修正する必要があったわけですが,意味が明確なの ですから,そういう関数もありそうです。そう,あるんです。それは,                   UBAOUND(x) という関数です。UpperBOUND つまり上限という意味の関数です。これを使うは,次のよ うなプログラムに修正することができます。 CLS INPUT "Size of Data "; Num DIM x(Num) FOR i = 1 TO UBOUND(x)   x(i) = RND NEXT FOR i = 1 TO UBOUND(x)   PRINT x(i); NEXT PRINT max = 0 FOR i = 1 TO UBOUND(x)   IF x(i) > max THEN max = x(i) NEXT PRINT "max = "; max なお,このプログラムの場合には,Num という変数を使ってもいいんですけどね。

12−3 FUNCTIONを作ろう −引数の概念に注意−

 さて,前回,FUNCTION文というのをやりましたね。上記のプログラムもFUNCTIONを使っ てみる手もあるように思います。メインを次のようにしてみましょう。そして,これで稼 働するようにするには,FUNCTION文をどのように作ったらいいか考えてみてください。 CLS INPUT "Size of Data "; Num DIM x(Num) FOR i = 1 TO UBOUND(x)   x(i) = RND NEXT FOR i = 1 TO UBOUND(x)   PRINT x(i); NEXT PRINT max = GetMax(x())             ← x()という表記はミスではない。 PRINT "max = "; max             行列を渡すときには,こう表す。 作るべきFUNCTION文は, FUNCTION GetMax(x()) ..... END FUNCTION さて,ここで一つ注意しておきます。上記のプログラムでは,Num という変数を使っても ,UBOUND(x) を使っても良かったのですが,今回のFUNCTION文では,Num は使えません。 何故でしょう。それは,             メインとFUNCTIONは別のプログラム ですから,           メインのNum とFUNCTIONのNum は別の変数 だからです。 両方は独立ではありますが,全く無関係では意味がないので,いくつかの変数は受渡しを しています。具体的には,             メイン : max = GetMax(X())             FUNC  : FUNCTION GetMax(x()) という記述の部分です。これによって,メインの方の変数 x()のデータをFUNCTIONの方の データ x()として扱うよということです。  また,ここで注意する必要があるのは,変数の名前は一致させる必要はありません。名 前が違っていても,目的が同じならば,OKなのです。このような変数のことを,「引数」 といい,詳しくは,メインの方を実引数,FUNCの方を仮引数といいます。  例えば,次のようなプログラムはOKです。 CLS INPUT "Size of Data "; Num DIM y(Num) FOR i = 1 TO UBOUND(x)   y(i) = RND NEXT FOR i = 1 TO UBOUND(x)   PRINT y(i); NEXT PRINT max = GetMax(y())       ←−−+ PRINT "max = "; max        | 名前が違う。                   | メインのy() をFUNCの x()に代入するという FUNCTION GetMax(x())     ←−−+ような気持ち。 (本当はちょっと違うけど) .....

12−4 「やってること」が分かるようなメインがいいよね

 さて,ところで,元のプログラムのメインは次のような感じに書けると分かりやすいで すよね。 CLS DIM x(100) 配列x() に乱数で値を定義せよ 配列x() を表示せよ max = GetMax(x()) PRINT "max = "; max このままでは無理ですが,次のように書くことはできます。 CLS DIM x(100) CALL SetRND(x()) CALL Show(x()) max = GetMax(x()) PRINT "max = "; max  そうか,そういう便利な SetRND とか Show っていうのがあるのかと思うかもしれませ んが,そんなものは「ありません」。  そうじゃなくて,そういうのを「作る」んです。FUNCTION文のときと同じで,そういう ものを作ることによって,プログラムがすっきりと見えるようになり,全体が構造的にな っていくわけです。

12−5 SUB文

 さて,どうやって「作る」か。それを SUB文といいます。具体的に,作った例から 話をする方がいいと思うので,そうしましょう。 SUB SetRND(x()) FOR i = 1 TO UBOUND(x)   x(i) = RND NEXT END SUB こうすることによって, x()をもらったときの「お仕事」をSUB によって行うわけです。 さて,同様にして,Showを作ってみてください。

12−6 ソーティング

 さて,今までは,「最大値」を求めることをしてきましたが,乱数でいろんなデータが 並んでいるという状況だったら,「整列」させてみたいですよね。そういうことを,「ソ ーティング」と言います。  典型的なプログラムを以下に書きます。 DIM x(100) FOR i = 1 TO 100   x(i) = RND NEXT FOR i = 1 TO 100   PRINT x(i); NEXT PRINT FOR i = 1 TO 100   FOR j = 1 TO 100     IF i < j AND x(i) > x(j) THEN SWAP x(i), x(j)   NEXT NEXT FOR i = 1 TO 100   PRINT x(i); NEXT PRINT ここでのSWAPというのは,「取り替える」という意味です。 さて,これを,メインが次のようになるようにしてみましょう。 CLS DIM x(100) CALL SetRND(x()) CALL Show(x()) CALL Sort(x()) PRINT CALL Show(x())

12−7 ソーティングの結果を目で見る

 数値で見てもつまらないですね。じゃあ,こうしましょう。もちろん,他のSUB も使い ますが,以下では省略しています。 SCREEN 12 CLS DIM x(100) CALL SetRND(x()) CALL DispGraph(x(), 0, 200) CALL Sort(x()) PRINT CALL DispGraph(x(), 200, 200) SUB DispGraph (x(), StartY, height)   ub = UBOUND(x)   dx = 640 / ub   FOR i = 1 TO ub      LINE ((i - 1) * dx, StartY)-(i * dx, StartY + x(i) * height), , B   NEXT END SUB

12−8 ソーティングの様子を目で見る

どうせなら,その様子も見たいですよね。こう修正してみましょう。 SCREEN 0 CLS DIM x(100) CALL SetRND(x()) CALL DispGraph(x(), 0, 200) CALL DispGraph(x(), 200, 200) CALL Sort(x(), 200, 200) PRINT CALL DispGraph(x(), 200, 200) SUB Sort (x(), StartY, height)   ub = UBOUND(x)   dx = 640 / ub   FOR i = 1 TO UBOUND(x)     FOR j = i TO UBOUND(x)      IF x(i) > x(j) THEN       LINE ((i - 1) * dx, StartY)-(i * dx, StartY + x(i) * height), 0, B       LINE ((j - 1) * dx, StartY)-(j * dx, StartY + x(j) * height), 0, B       SWAP x(i), x(j)       LINE ((i - 1) * dx, StartY)-(i * dx, StartY + x(i) * height), , B       LINE ((j - 1) * dx, StartY)-(j * dx, StartY + x(j) * height), , B      END IF     NEXT   NEXT END SUB

12−9 もっと効果的なソーティングはないの(1)

 つまらない修正のように見えますが,どんな効果があるでしょう。 SUB Sort (x(), StartY, height)   ub = UBOUND(x)   dx = 640 / ub   FOR i = 1 TO UBOUND(x)     FOR j = UBOUND(x) TO i STEP -1      IF x(i) > x(j) THEN       LINE ((i - 1) * dx, StartY)-(i * dx, StartY + x(i) * height), 0, B       LINE ((j - 1) * dx, StartY)-(j * dx, StartY + x(j) * height), 0, B       SWAP x(i), x(j)       LINE ((i - 1) * dx, StartY)-(i * dx, StartY + x(i) * height), , B       LINE ((j - 1) * dx, StartY)-(j * dx, StartY + x(j) * height), , B      END IF     NEXT   NEXT END SUB

12−10 もっと効果的なソーティングはないの(2)

 何をやっているんでしょうね。 SUB Sort (x(), StartY, height)   ub = UBOUND(x)   dx = 640 / ub   FOR i = 1 TO UBOUND(x)     Min = i     FOR j = i TO UBOUND(x)       IF x(Min) > x(j) THEN Min = j     NEXT     j = Min       LINE ((i - 1) * dx, StartY)-(i * dx, StartY + x(i) * height), 0, B       LINE ((j - 1) * dx, StartY)-(j * dx, StartY + x(j) * height), 0, B       SWAP x(i), x(j)       LINE ((i - 1) * dx, StartY)-(i * dx, StartY + x(i) * height), , B       LINE ((j - 1) * dx, StartY)-(j * dx, StartY + x(j) * height), , B   NEXT END SUB  なお,ソーティングには,他にもいろいろな技法があります。ここでは,それを学習す ることが目的ではないので,あまり触れませんが,関心がある人は調べてみてください。 アリゴリズムによって,こんなにも速度が変わるのかと感心するものがいろいろとあるは ずですし,考えるといろいろな方法があるものだと感心すると思います。