まあ、具体的な計算方法を記述してなかったところに問題があったわけですが。
前回のrand関数の考察では、どのようにしてコイン乱数(コインが作る乱数のことで、要するに0または1のどちらかを出力する関数が作る系列というか数列と思っていただければ)を作っていたのかというと
r = rand()%2; ・・・ (*)
mod2をとっていただけなんですよ。わかりやすく言えば、「2で割ったあまり」です。もっとわかりやすく言えば、偶数なら0、奇数なら1を出力しただけなんですが、どうやらこれが間違いだったらしく、その驚愕の新事実に気づいたのが今日の午後3時頃。
VisualC++のrand関数は、0〜32767までの整数値をランダム(正確には〜ってのは省略)に出力するんだけど、この32767ってのは215-1ということで、15ビットなわけですね。だから、一度関数を呼び出せば2進列で15個の0と1の組み合わせを入手できるので、(*)の方法で同時に1文字ずつ0または1の値を取得するよりも、この15ビットをフルで活用した方が無駄がないということは、まあ当たり前だと思います。
その当たり前のことにさっき気がついたので、下図のようなことを考えて15倍(゚д゚)ウマーしたわけですよ。

今までは最も右に当たる部分(最下位ビット)だけを取り出して1倍(゚*゚)マズーだったところを、今度はそれの15倍(゚д゚)ウマーというわけですね!
そして、取り出した系列の一番左から順に、その乱数列の性能を簡単に確かめていったんですが...検証方法は、各a[i]の2万ビット(0と1が合計2万個ある)に含まれる1の数を数え、それを65536回繰り返し、その結果をヒストグラムに表してます。ようは、きれいな山型(正規分布)をしていればとりあえず性能がよいということですね。ただし、ちゃんとした検証方法ではないのでご注意を。

これはひどいな。グラフの1〜15というのは、それぞれがa[1]〜a[15]に相当してます。
左側に行けば行くほど、乱数の性能が悪くなっていると言うことが一目瞭然ですね!! 右端の値だけを使って、これを乱数として使用するぶんには、案外それほど性能に関しては気にしなくても良さそうだけど、一般人が手っ取り早く乱数を使う時なんて、普通は俺みたいに(*)のように使うだろうから、ちょっとこれは問題があるんじゃないかなと。
で、同じような考えで、メルセンヌ・ツイスタ(Mersenne Twister−MT)法でもやってみました。rand関数が15ビットしか出力できなかったことに対し、MT法では、なんとその倍の32ビットの値を出力できる激(゚д゚)ウマーな乱数ジェネレータだったりします。
結果はこんな感じ

おおお、どこを切っても同じ分布になってるしヾ( ゚д゚)ノ"
rand関数を使うときはこんな感じに分割して使うことはないだろうけど、単純に考えて、これらの性能の良い列と、悪い列をまぜこぜで使ってるんだから、その合成された結果というのは必ずしも良い列とはなりませんよね!! そんなわけで、rand関数がいかに危険な関数かということが、わかったかと思います。そして、本当に正しく正確に乱数を出力したいならば(←ややこしいな)、MT法を使った方がずっと良いと言うことが、このことからも理解できたと思います。
って言うと、うちのゼミでは「いやそれだけの検証じゃ全然だめだよ。もっと数学的に証明しないと」ってつっこまれるんだよなwwwww
まあ、このテーマで次回のゼミを発表したいと思うので、興味があったらうちの研究室に来てみてください。熱烈歓迎は・・・たぶん、発表に必死でしませんというかできませんwwwww
(rand() >> 4) % 2
みたいな。
当然、自分でキチンとした計算のrand関数に置き換えてしまう方が、適切ではありますが。
これぐらいの簡単な処理で、そこそこ安定した出力が得られるなら、フリーソフトのゲームレベルならこれで十分ですね!
研究で複雑な計算をするときや、[0,1]での連続値が欲しい場合、あとは市販ソフトあたりでは、確かにMT法あたりを導入しないとやっていけませんが、まあ、rand関数の周期に収まる程度の乱数ぐらいしか使わない個人ゲームならば、そこまでの精度はそこまで必要ないかな。
後輩に rand() の精度について教えようと思ってググったら2番目に出てきたので、旧ブログだけど記念真紀子。