From: Michael Morin Date: 2008-08-18T07:13:15+09:00 Subject: Re: [QUIZ] Not So Random (#173) brabuhr@gmail.com wrote: > On Fri, Aug 15, 2008 at 11:33 AM, Matthew Moss wrote: >> ## Not So Random (#173) >> >> The first part is to create a wrapper around the random number >> generator `rand`, supporting the appropriate parameter (i.e. the >> parameter intrinsic to `rand`). Your wrapper should implement two >> additional functions: `next` which returns the next random number, and >> `reset` which restarts the sequence. >> >> The second part is a little trickier: creating multiple, concurrent, >> _reproducible_ sequences of pseudorandom numbers isn't so easy. As >> convenient as the built-in generator is, there is only one seed. > > Since a single Ruby process only has one PRNG, slave off an extra > process for each Random class: > > #!/usr/bin/env ruby > > require 'rubygems' > require 'slave' > > class Random > def initialize(ceiling, seed = nil) > @ceiling = ceiling > @seed = seed || rand(2112) > @slave = Slave::new{ > lambda {|reset| > if reset > srand(@seed) > else > rand(@ceiling) > end > } > } > self.reset > end > > def next > @slave.object.call(false) > end > > def reset > @slave.object.call(true) > end > end > > require 'test/unit' > > class RandomTest < Test::Unit::TestCase > def test_001 > x = Random.new(100, 2112) > assert_equal( [38, 1, 5, 57, 11], Array.new(5) { x.next }) > assert_equal( [ 1, 31, 3, 56, 14], Array.new(5) { x.next }) > x.reset > assert_equal( [38, 1, 5, 57, 11], Array.new(5) { x.next }) > end > > def test_002 > x = Random.new(100, 2112) > assert_equal( [38, 1, 5, 57, 11], Array.new(5) { x.next }) > y = Random.new(100, 1221) > assert_equal( [ 5, 99, 88, 48, 86], Array.new(5) { y.next }) > x.reset > assert_equal( [38, 1, 5, 57, 11], Array.new(5) { x.next }) > assert_equal( [34, 28, 72, 77, 87], Array.new(5) { y.next }) > assert_equal( [ 1, 31, 3, 56, 14], Array.new(5) { x.next }) > end > end > > > Loaded suite foo > Started > .. > Finished in 0.251163 seconds. > > 2 tests, 8 assertions, 0 failures, 0 errors > This is probably the cleanest solution you can get without implementing your own PRNG or mucking around in C code to copy the internal state of the PRNG. As long as it uses fork, it shouldn't eat up RAM or anything. The popen solution probably would if a large number of Random objects were created. -- Michael Morin Guide to Ruby http://ruby.about.com/ Become an About.com Guide: beaguide.about.com About.com is part of the New York Times Company