awkで乱数を使いたい - rand(), srand()

awkで乱数を使いたい時は rand() 関数を使います。

$ echo | awk '{print rand()}'
0.827331

rand() は0~1までの乱数を発生させます。そのため、例えば1〜10までの値にしたい時は以下のように書く必要があります。

$ echo | awk '{print int(rand()*10)+1}'
7

このように非常にシンプルな関数なのですが、注意しなければならない挙動があります。

同じ乱数しか生成しない問題

awkにはgawkやnawk, mawkなど色々な実装があるのですが、一部の実装では乱数の値がビルド時に決定してしまい、同じ値しか返さないことがあります。例えば、Macに入っているawkコマンド、nawk(new awk)がこれに当てはまります。以下、Macで複数回同じrandコマンドを実行した例を貼り付けます。

~$ echo | awk '{print rand()}'
0.840188
~$ echo | awk '{print rand()}'
0.840188
~$ echo | awk '{print rand()}'
0.840188

rand() が返す値は常に一定です。

次に、Ubuntuのawk、gwk(GNU awk)の例を貼り付けます。

$ echo | awk '{print rand()}'
0.0983234
$ echo | awk '{print rand()}'
0.456071
$ echo | awk '{print rand()}'
0.456071
$ echo | awk '{print rand()}'
0.315948

異なる値が生成されています。が、一部値が被っているのが気になります。

解決策

nawkでもgawkでも解決策は同様で、srand() 関数でシード値を毎回設定するようにします。

$ echo | awk 'BEGIN{srand()} {print rand()}'
0.550617

こうすれば処理のたびに srand() 関数が実行され、 rand() で使用されるシード値が毎回新しい値になります。

以下のように10回連続で rand() しても毎回違う値になります。

$ seq 10 | awk 'BEGIN{srand()} {print rand()}'
0.787021
0.291794
0.777201
0.619548
0.505395
0.399438
0.888092
0.218917
0.96164
0.751791

srand()を除いて上のコードを実行するとnawkでもgawkでも同じ値になるのでぜひ試してみてください。ではでは!

参考:

Numeric Functions (The GNU Awk User’s Guide)