Repeatable randomness in Ruby
I know I can "restart" my rand
calls by calling srand
with a seed, but surely this would affect future开发者_StackOverflow社区 calls to rand
by other library methods, including cryptographic methods?
How can I repeat my randomness in certain places and still ensure that the rest of my code isn't affected?
(Ruby 1.9.2) You could serialize a random generator, store it in a file and provide the file with your program.
Create the file:
File.open('random_generator.marshal', 'w'){ |f| Marshal.dump(Random.new, f) }
use the random generator in your program:
f = File.open( 'random_generator.marshal', 'r' )
r = Marshal.load( f )
f.close
10.times{ puts r.rand } #repeatable
Use the simple-random gem.
(in ruby 1.9.3) there is a simplier solution ussing Random
.
You need to use r = Random.new(seed)
to get an object that you can use to generate randomness calling r.rand
. this is repeateble, and will only affect calls to r.rand
not Kernel.rand
.
Well, you could implement your own PRNG that didn't use the system version. There's plenty of literature on the subject of how to do this, from the simplest linear congruential to the Mersenne twister.
In fact, since Ruby is open source, you could actually sneak a peek (see random.c
) at how it does random numbers and re-implement that using information separate from the system version.
rand():
...Kernel::srand may be used to ensure repeatable sequences of random numbers between different runs of the program....
srand():
Seeds the pseudorandom number generator to the value of number.to_i.abs. ... By setting the seed to a known value, scripts can be made deterministic during testing....
You can store your seed value, and the number of iterations that the user has made, then at a later time reseed with that value, then loop the number of times they've used it before to step over the previous values, and land on your next value in the sequence. It's the only way I know of to try to recover the sequence. If you are concerned about other routines/threads then grab the original seed and store it before you set srand with yours, get your next number, then restore the original seed.
If you are concerned about affecting the randomness about other routines that rely on it, I think the authors of those routines should have done something to ensure they were dealing with a truly random seed. You really can only concern yourself about your code and not killing the system. Beyond that the responsibility becomes theirs.
If you're using JRuby, you can just instantiate a java.util.Random
.
精彩评论