-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
The three rules of Ruby Quiz 2:
1. Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at<http://splatbang.com/rubyquiz/>\.
3. Enjoy!
Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.
Great to have the quiz back! This one looks fun.
Fred
···
On 15 Aug 2008, at 16:33, Matthew Moss wrote:
## Not So Random (#173)
As part of Ruby's standard library, we have access to a good
pseudorandom number generator (PRNG), the [Mersenne twister][1]. (In
particular, the MT19937 variant.) Ruby provides two kernel functions
to make use of this generator: `srand` and `rand`. This week's quiz
involves generating random numbers in a predictable manner.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. So, for example:> x = Random.new(100)
=> #<Random:...>> Array.new(5) { x.next }
=> [51, 92, 14, 71, 60]> Array.new(5) { x.next }
=> [20, 82, 86, 74, 74]> x.reset
=> nil> Array.new(5) { x.next }
=> [51, 92, 14, 71, 60] # after reset, sequence restartsYou may do this as a class, as depicted here, or as a function,
lambda, code block... whatever you like.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. For
example, assume we have two `Random` objects, created as shown above,
`x` and `y`.> x = Random.new(100)
=> #<Random:...>> Array.new(6) { x.next }
=> [51, 92, 14, 71, 60, 20]> y = Random.new(100)
=> #<random:...>> Array.new(6) { y.next }
=> [66, 92, 98, 17, 83, 57]> x.reset
=> nil> Array.new(2) { x.next }
=> [51, 92] # ok: sequence restarted as requested> Array.new(2) { y.next }
=> [14, 71] # fail: this is part of _x_ sequence> Array.new(2) { x.next }
=> [60, 20] # more fail: _x_ is now [51, 92, 60, 20]? wrong...The reason for the failure should be obvious: my current
implementation of `Random` just blindly uses `srand` and `rand`
without considering that there may be multiple instances of `Random`.So, for this second part, expand your wrapper to support concurrent
use. Please note that you are required to make use of the built-in
generator: you should not implement your own PRNG.One final note... It is up to you whether the seed for each wrapper
will be user-settable or hidden (as in my examples above). However, if
hidden, each wrapper should have a different seed. (Generated
randomly, perhaps?)[1]: Mersenne Twister - Wikipedia
--
Matthew Moss <matthew.moss@gmail.com>