どう書く?(重複無し乱数)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回でも同じ数字がでたら、後は円環のようにぐるぐる回るだけ)

すごいバカバカしいことを書いてました。ゴメンナサイ><ゴメンナサイ><

メモ

It also is implemented in gLib and the standard libraries of at least PHP, Python and Ruby.

?膨大な数=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回では足りなそう。

まだ、考え中