awkで0~1の乱数を生成する
シェルスクリプトを書いていて、ふと0~1の乱数をお手軽に生成したくなったので、実験結果をメモ.
awkには組み込みでrand()という関数が用意されていて、例えば以下のような形で呼び出すたびに0~1の範囲の乱数を生成してくれる.
awk 'BEGIN{ srand('"$RANDOM"'); print rand() }'
ここでは環境変数RANDOMを組み込み関数srand()のseedとしている.組み込み関数についてはman awk
を叩く.
筋が良いのか悪いのかわからないが、とりあえず上記のような結論に至ったのは、以下のサンプルコードの実行結果による.
実行結果は以下の通り.
$ bash awk_rand.bash ---> sleep 0 0.104709 0.104709 0.104709 0.104709 0.104709 0.104709 0.104709 0.104709 0.104709 0.104709 ---> sleep 0.5 0.104709 0.104709 0.236247 0.236247 0.367785 0.367785 0.499323 0.499323 0.630861 0.762398 ---> sleep 1.0 0.762398 0.893936 0.025474 0.157012 0.28855 0.420087 0.551625 0.683163 0.814701 0.946238 ---> srand($RANDOM) 0.73843 0.445421 0.237373 0.537946 0.900747 0.589343 0.0254097 0.139673 0.721284 0.539107
srand()にseedを設定しないままfor文で回すと出力される乱数が変化しなかった.
上記の通り、またman awk
にも書いてある通り、srandは時間をseedにしているので、乱数は1秒単位でしか変化しない.
というわけで、とりあえず環境変数RANDOMをseedとして、for文で回しても生成される乱数が毎回変化するようにした.
ところで、この方法で生成される乱数の精度はどの程度か気になる.
が、厳密な乱数精度の評価方法をすぐに思い出すことも、思いつくこともなかった.
ここでは視覚的にバラバラの値が出力されているっぽいことを確認してお茶を濁しておく.
#!/bin/bash plotfile="awk_rand.plot" [ -e $plotfile ] && rm $plotfile for loop in `seq 10000` do output=`awk 'BEGIN{ srand('"$RANDOM"'); print rand() }'` echo "$loop $output" >> $plotfile done gnuplot <<- EOF set terminal png set output "awk_rand.png" plot "$plotfile" EOF
見た目はこんな感じ.
相加平均
$ awk 'BEGIN{ sum=0 } { sum+=$2 } END{ print sum/NR }' awk_rand.plot 0.50121
標本分散
$ awk 'BEGIN{ sum=0; ave=0.50121 } { sum+=($2-ave)^2 } END{ print sum/NR }' awk_rand.plot 0.0846204
$ awk 'BEGIN{ sum=0; ave=0.50121 } { sum+=($2-ave)^2 } END{ print sqrt(sum/NR) }' awk_rand.plot 0.290896
今日も今日とてawk先生のお世話になった.