次へ: 4.2 ランダムな整数列 上へ: 4 課題文の作成 前へ: 4 課題文の作成 (PDF ファイル: awk2.pdf)


4.1 乱数生成関数

課題文は、毎回同じ文字列ではおもしろくありませんから、 毎回違った文が得られるように「乱数」を利用して作ることにします。

なお、実際のタイプ練習では、 ランダムな文字列よりも意味のある文字列の方が入力しやすいので、 課題文は意味のある文章例などを利用する場合もありますが、 ここでは簡単のためランダムな文字列を使うことにします。

課題文の文字は、簡単のため a$\sim$z (小文字) と空白からなる文字列とします。 空白は適当に入れてやる方が入力しやすいと思いますので、入れることにします。

AWK で乱数を使う場合は、rand(), srand() という関数を使用します。

これらを例を用いながら説明します。 まず、実際に rand() がどのような値を返すのか見てみることにします。
  BEGIN{ for(j=1;j<=10;j++) print rand() }
というスクリプト test1.awk を
  awk -f test1.awk
と実行させます。このスクリプトは BEGIN{} ブロックしかないので、 AWK は BEGIN{} ブロック内を実行するとすぐに終了します。 for 文は C 言語と同じ構文で、 このスクリプトでは ``print rand()'' を 10 回実行しています。 print rand() は、rand() の返す実数値を 1 行ずつ表示するだけです。 rand() は引数はありません。 上のスクリプトの実行結果は以下のようになります (FreeBSD 4.7 上の gawk-3.0.3+mb1.09 の場合)。
 % awk -f test1.awk
 0.487477
 0.0715607
 0.00395315
 0.832913
 0.765252
 0.599829
 0.131783
 0.88603
 0.0732417
 0.34195
これでランダムな数字の列が作られるのですが、 実はこれはランダムに見えるだけで、 ある規則 (数式) で生成されている疑似乱数列にすぎません。 よって、もう 1 回上のスクリプトを実行すると これと同じ乱数列が生成されてしまいます。 これでは、課題文をランダムにできても、 毎回実行の度に課題を変えることができません。

そこで乱数列を変化させるのに使われるのが srand() で、 srand() は、疑似乱数列をどこから始めるのかを決める関数です。 しかし、引数として一定の数字を与えてしまうと、 それによってまた一定のところから始まる同じ乱数列が生成されてしまいます。 実は、srand() は引数を省略すると、 「srand() を実行した時刻 (単位は秒)」 を使って rand() の疑似乱数列の初期値を設定してくれますので、 これによって実行の度に違った乱数列を得ることができます。

今度は、

  BEGIN{ srand(); for(j=1;j<=10;j++) print rand() }
というスクリプト test2.awk を実行してみます。
 % awk -f test2.awk
 0.270585
 0.666318
 0.724231
 0.813703
 0.810067
 0.0925101
 0.00122359
 0.722831
 0.084683
 0.953172
このスクリプトは、実行時刻が少なくとも 1 秒以上違っていれば、 実行する度に違った乱数列を生成します。 この例のように、srand() は、rand() を実行する度に呼びだす必要はなく1、 そのプログラムの中で最初に 1 回だけ呼びだします。

なお、AWK の「関数」は、C 言語同様、値を返してくれる関数と、 値を返さず何らかの作業を行うだけの関数の 2 種類が あります2。 AWK では C 言語同様両方とも関数と呼びますが、 プログラム言語によっては、これらをそれぞれ「関数」「手続き」のように 区別することもあります。 その意味では、rand() は関数、srand() は手続き、となります。

また、C 言語でも、通常この rand(), srand() と同様の関数が用意されていますが、 C 言語では普通 srand() (に相当するもの) は引数を省略することはできず、 引数として現在の時刻を実際に与えます。


次へ: 4.2 ランダムな整数列 上へ: 4 課題文の作成 前へ: 4 課題文の作成
竹野茂治@新潟工科大学
2006年4月27日