−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
   応用数学II                         1995.10.20/21
   11.プロシージャという概念(1)FUNCTION文     飯島
              −さあ,後期の始まりだ−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

11−1 はじめに

 「試験」の結果を振り返ってみると,いくつかの教訓があるように思う。やっぱりと思 ったのは,「数学の問題にあわせて,プログラムをどう作ったらいいか」を理解している 人はほとんど満点になってしまうが,そこを掴んでいない人はとても低い点数になってし まう,ということ。前者の人はそのままのペースで進んでいただければいいわけですが, 後者の人のことをどう考慮しながら今後の授業を進めるか,やはりそれが一つの「課題」 だなと思っています。同時に,多少なりとも,試験の結果にショックがあった人は,「思 考方法」を身に付けることに前向きでいてください。

11−2 後期の方針と「評価」について

 前期の最初にも言いましたが,この授業の評価の中心となるものは,最終レポートです 。つまり,後期の終わりの方で,       自分なりのテーマを持ち,そのためのプログラムを自分で作る ということが中心になります。いくつかのテーマ例はそのときに提示する予定ですが,で きれば「自分でテーマを発見する」方がずっといいわけで,            やってみたいテーマを日頃から探すこと あるいは,          「こんなのできますかね」と相談してみること がいいでしょう。  プログラミングの目的はいろいろありますが,みなさんは,プログラマーになるわけで はなく,それなりの原理を習得できればいいわけだし,特に,数学の問題を考える道具と して使うには,どうしたらいいかというノウハウを取得することの方が大切でもあるので ,そういうことを実践的にやっていきたいと思っています。そういう意味で,  (1)中級プログラミングに到達するための基本的なこと  (2)いろいろな数学の問題へのアタック という二つが今後の柱になると思います。

11−3 「思考の流れ」が分かるようにプログラムを書くということ

 プログラムを書くときは,結構「熱く」なっていたりしますから,無我夢中で作ったり するわけですし,そのときは,「動けばいい」というのが第一の判断基準だったりします 。しかし,「熱しやすく冷めやすい」のが人の常。1週間もすれば,一体何を書いていた のか自分でも「読めない」代物になっていたりします。  プログラミングのプロにとっては,いろいろな「ワザ」があったりするのでしょうが, 我々「素人プログラマー」にとって最も大切なのは,「何を考えて使ったのかが,後で読 んでも分かるようなプログラミングの作法」を身に着けることです。  まずは,その素材として,前回の試験の問題の中から,               「約数の個数を調べる」 という問題を考えてみたいと思います。 (1)紙と鉛筆でやるとしたらどうするか から 疑似コード まで  いろいろな方法がありますが,一番基本的な考え方をすれば, 要するに,  nが与えられたら,1〜nまでの数字について,「割り切れるか」をチェックすればい いわけですよね。  input n  for i = 1 to n    もし n が i で割り切れたら i を表示しよう  next というわけです。 「もし n が i で割り切れたら i を表示しよう」 なんてプログラムじゃないと言ってはいけません。「こういう仕事をしてくれるといいん だけど」という内容を,言葉でいいからきちんと書く,そして全体の流れを少しでも明確 化し,すべき仕事を細分化するということが,プログラムを書くための第一歩です。  ちなみに,こういう「プログラムじゃないけれど,それらしい文章」のことを,「疑似 コード」なんて言うこともあります。さて,   「もし n が i で割り切れたら i を表示しよう」 というのは,具体的には,どうプログラム化したらいいでしょう。 一つの案は,    if n mod i = 0 then print i です。逆に,こういうプログラムがあったら,上のように「読める力」も必要ですね。 (2)変数の名前を分かりやすくする  この程度の長さなら,どんな変数名を使っても,ほとんど問題ないですが,少しずつ長 くなるにつれ,変数が増えると,どれが何を指しているのかが分かりにくくなってきます 。たとえば,このプログラムの場合も,問題を少し修正し, 「nを入力し,n〜n+100までの数について,その約数の個数(のみ)を表示する」 ことにしてみましょう。  まずは,自分なりにプログラムを作ってみることにしよう。  プログラム例(1)  cls  input n  for k = n to n + 100    x = 0    for i = 1 to k      if k mod i = 0 then x = x + 1    next    print k ; ":"; x;  next もちろん,これで動きます。しかし,x というのは何だろうかというのが少し気になりま す。たとえば,次のものと比較してみましょう。  cls  input n  for k = n to n + 100    NumOfFactor= 0    for i = 1 to k      if k mod i = 0 then NumOfFactor = NumOfFactor + 1    next    print k ; ":"; NumOfFactor;  next  今度は,NumOfFactor という名前を使っているだけで,「約数の個数」かなと分かるで しょう。いや,英語は嫌いという人は,YakuNoSuu でもいいでしょうし,Kosuu でもいい かもしれません。  ところで,こんなプログラムが書けるともっと楽ですよね。 例(2)  cls  input n  for k = n to n + 100    print k ; ":"; NumOfFactor(k);  next  大体「読める」でしょ。そう,「読める」ということが大事なんです。ところで,これ じゃ, いくらなんでも「動きません」よね。そう,大体,                  NumOfFactor(k) なんていう,虫のいい関数なんでQBASICにはありません。しかし,QBASICのいいところは ,そういう虫のいいものが欲しかったら,「自分で作ることができる」というところにも あるんです。そして,それは普通のBASIC ではちょっとできないことなんです。

11−4 FUNCTION文を作る

 目的は,  cls  input n  for k = n to n + 100    print k ; ":"; NumOfFactor(k);  next というプログラムが動くようにすることです。そして,そのためには,                   NumOfFactor という関数を作ることです。では,次の手順で作りましょう。  (1) まずは,上記のプログラムを作る。  (2) NumOfFactor の部分にカーソルを移動する。    (カーソルっていうのは,キーボードを押すと動く「点滅」する部分のこと)  (3) Alt キーを押す。  (4) 隣の「Edit」の部分に移動。  (5) 下に引っ張って,「New FUNCTION」に移動。  (6) リターンを押す。  (7) New FUNCTION で Name 「NumOfFactor 」と出るので,そのままリターン  (8) すると,次のような画面が出る。    FUNTION NumOfFactor    END FUNCTION  (9) これを次のように修正する。    FUNTION NumOfFactor (k)      for i = 1 to k        if k mod i = 0 then Num = Num + 1      next      NumOfFactor = Num    END FUNCTION   なお,行を増やすには,増やしたいところでリターンを入力すればいいでしょう。   さあ,動くかな。

11−5 見やすくしよう

             −使いやすくするための工夫−  結果を見ると,ちょっとみにくいですね。「見やすく」しましょう。アルゴリズムとい う意味では本質的じゃないけど,こういう工夫には慣れておくといいと思います。  例えば,1行に5つずつ表示するようにしましょうか。そのためには,メインの部分を 次のように修正すればいいでしょう。  cls  input n  for k = n to n + 100    num = ct mod 5    print tab(num * ○);k ; ":"; NumOfFactor(k);    ct = ct + 1  next ここで,○の部分には,自分なりの数値を入れてみてください。どんな値だといいでしょ う。  そうそう,それ以前に問題があるかもしれませんね。つまり,          メインとFUNCTION文との切替えをどうするんだ ということです。それには,                 F2キーを押せ。  じゃあ,やりましょうね。

11−6 問題を考えよう

 「問題を考える」というのは,変だけど,変じゃないんです。ここが,「コンピュータ 利用の真骨頂」です。  つまり,「道具が変わると,今までの問題が当たり前のように解けることもある」  しかし,あまりに簡単に解けちゃうと,「こんなもんか」と思うだけじゃなくて,              「ついでにこんなのもどう」  って,欲張りになるのが人間でしょ。  そう,そして,それにつられて,いろいろと問題を発見していくと,        「今までは解こうと思わなかった問題を見つけられる。」 つまり,      「コンピュータを使うは初めて解けるような問題が見つけられる」 あるいは,そのための突破口が見つかるようになるわけです。  たとえば,  「Q1:1000までの約数の個数の分布を調べよう」  「Q2:100000までの素数の分布を調べよう」 などということを考えたりします。また,他にも,あるかもしれませんよね。              「自分の問題を見つけよう」

11−7 改良しなきゃ

 さて,欲を出してくると,いろいろな問題が出てくることがあります。プログラムなん ていうのは,基本的には,                 「動けばいい」 んだから,最初からアルゴリズムの改良なんて考える必要はないんだけど,100000 なんていうのを扱うと,「止まったようだ」と感じるほど,遅くなったりする。こういう ときに,金持ちだったら,            「もっと速いパソコンを買ってこい」 と大須に車を飛ばすのも一つの手なんだろうけど,残念ながら我々は貧乏だ。しかも,我 々には「数学用の頭がある(?)」。                「貧すれば鈍する」 なんていう情けない言葉もあるけれど,やっぱり,               「必要は発見の母である」 というような言葉に愛着を持てるような人間でいたい。なんていうことを思いつつ,「改 良」をしてみましょう。  こういうときには,「原理を再考察」するのに限ります。そして,そこでの無駄を考え ます。  「nが与えられたら,1〜nまでの数字について,「割り切れるか」をチェックすれば   いいわけですよね。」 なんていうのうてんきな方針だからだろうと考え,「実際にやってみます」。  すると,100のときは,  1,2,4,5,10,20,25,50,100  どこに一番「無駄」があるでしょう。  そう,50〜100の間は「空白」ですね。しかも,それは「当たり前」。  じゃあ,FUNCTIONの部分を次のようにできるじゃないですね。    FUNTION NumOfFactor (k)      Num = 2      for i = 2 to k \ 2             ← \はバックスラッシュにしてね。        if k mod i = 0 then Num = Num + 1      next      NumOfFactor = Num    END FUNCTION  さあ,これでどの程度の「高速化」ができたかな。  あれ,それとも,この「高速化」は以前にどこかでやったような気もする。  まあいいか。いずれにしても,ここを直すだけで,       「2倍の速度のコンピュータを買わずに済むことになった。」  やっぱり貧乏人は「頭」で勝負。???  本当はもっと「高速化」できるんだよね。どうしたらいい?

11−8 ところで,FUNCTION文て何だろう

 いろいろな答え方がありますが,作る側の利点という観点で答えると, (1)こんなのがあるといいけど,という気持ちのままにプログラムを書ける。 (2)標準ではFUNCTIONも「作れる」 (3)メインとFUNCTION文は「別のプログラム」なので,作業を細分化できる。    詳しくなるが,    メインの中での変数名とFUNCTION文の中での変数名は「同じものでも違う」    つまり,まったく分業ができる。 (4)このことによって,「長いプログラム」も小さなものの積み重ねでできるので,    かなり大きなものでも結構容易に作れる。    30行以下:初級。どんな言語でもほぼ一緒    数百行  :BASIC などの実質的な限界。          この辺でもQBASICなどならすいすい。          つまり,FUNCTIONなど「プロシージャ」という概念があるものなら。    数千行  :QBASICなどの実質的な限界。          FUNCTION名などがかち合ってくる。          これを越えて,数万行でもOKとするためには,C++などの言語が          必要になってくる。