どう書く?(重複無し乱数)3
追記
これで、偏りが生じるsortなことははっきり分かる。
def myrand (rand+0.5).to_i end p (1..100000).inject(Hash.new(0)){|h,e| h[[1,0].sort_by {myrand}]+=1; h} #結果 #{[1, 0]=>74999, [0, 1]=>25001}
参考までに
x=lambda {|arr| arr.each_index {|i| j=rand(i+1); arr[i], arr[j] = arr[j], arr[i]}} p (1..10000).inject(Hash.new(0)){|h,e| h[x.call([1,0])] +=1; h} #=>{[1, 0]=>4957, [0, 1]=>5043}
<元の記事のはじまり>
sort_byでの重複無し乱数を生成では、膨大な量の数を入れた場合に偏りが生じます。
ふたつの勘違いから、そんなに偏りは生じないのではないかと思ってました。(すごい頭わるいです。)
ふたつの勘違い
- 順序が一定ではない=「2つの数字が重なった場合、前になる確率と後ろになる確率が半々になる(ぐらいの誤差しか生じない)」と思っていたこと。
- (順序の組換えが全て等確率で起こると思ってたってこと。)
- randを「開けるたびに違った数字を表示してくれる魔法の箱」のようなものだと思っていたこと。
- 周期があるということに気づきませんでした。
- (1回でも同じ数字がでたら、後は円環のようにぐるぐる回るだけ)
すごいバカバカしいことを書いてました。ゴメンナサイ><ゴメンナサイ><
メモ
- rubyのrandではメルセンヌ・ツイスタ(Mersenne twister)が使われている。
It also is implemented in gLib and the standard libraries of at least PHP, Python and Ruby.
- Mersenne twister
- 周期:2^(19937)-1
?膨大な数=2^(19937)以上の数?
-
- doubleそんなに桁数ない
- doubleの桁数から考えた方が良いかも
まだ、調査中
メモ2
偏りがあることを実際に目で見てみたい。
少ない種類の数しか返さない関数をつくって、それを使ってみれば良いのかもしれない。
こんな感じに
def my_rand(period=10) (rand*period).to_i end def bingo n (1..n).to_a.sort_by{|e| my_rand} end
bingoが返す配列の最初の位置だけでを、カウントすれば偏りが分かるのかな?
- 1000とか10000回では足りなそう。
まだ、考え中