Using custom random number generators with Ruby Array#shuffle/sample -
when using array#shuffle, ruby allows use of custom randomizer , provides class random
utilize it. following example uses class seed value of 48.
array = [1,2,3,4,5,6,7,8,9,10] array.shuffle(random: random.new(48)) # => [8,6,3,7,10,9,5,2,4,1]
i wrote small monobit test see how many times value appeared first in shuffled array.
deck = (1..10).to_a counts = hash.new(0) rng = random.new 50000.times counts[deck.shuffle(random: rng).first] += 1 end 1.upto(10) |card| puts "#{card}:\t#{counts[card]}" end
the output looks similar following:
1: 4942 2: 5100 3: 4938 4: 4960 5: 5024 6: 4992 7: 5184 8: 4930 9: 4916 10: 5014
suppose want replace pseudo-random number generator new class. since array#shuffle appears use random#rand in above example, seem straightforward implement new class act rng shuffling. here, implement new pseudo-random number generator simple wrapper around rand
:
deck = (1..10).to_a counts = hash.new(0) class foorandom def rand(max=nil) max.nil? ? kernel::rand : kernel::rand(max) end end rng = foorandom.new 50000.times counts[deck.shuffle(random: rng).first] += 1 end 1.upto(10) |card| puts "#{card}:\t#{counts[card]}" end
this, however, not operate expected. foorandom#rand
called, shuffling produces following distribution:
1: 0 2: 5423 3: 5562 4: 5544 5: 5512 6: 5569 7: 5535 8: 5595 9: 5524 10: 5736
as can see, array value 1 never appears in first position of array after array shuffled. have idea why?
there bug in ruby 2.0.0p0 limit off one.
this has been fixed in ruby 2.0.0p195, should upgrade installation.
Comments
Post a Comment