Control Your Randomness With `srand`

ruby
Posted on: November 23, 2012

While trying to track down a bug, I learned a neat Ruby trick for controlling randomness. Suppose we have the following code:

numbers = (1..1_000).to_a

3.times do
  puts "We chose number #{numbers.sample}"
end

Each time you run it, you'll see a different set of 3 numbers. Handy.

Of course, computers are actually deterministic; given the same program and the same starting conditions, they will produce the same results every time. What we call "random" is generally just pseudorandom; very hard to predict if you don't know the starting conditions, but absolutely predictable if you do.

The trick is to get a random seed into the starting conditions. According to the documentation, Ruby uses "a combination of the time [and] the process id" to do this by default. But you can set your own seed. For instance:

srand(1) # Or any number you like
numbers = (1..1_000).to_a

3.times do
  puts "We chose number #{numbers.sample}"
end

When I do that, I get 418, 17, and 1, every time.

This has a couple of neat implications:

  • If you're trying to track down a bug that depends on randomized behavior, you can reproduce those conditions by trying random seeds until you find one that triggers the bug.
  • If you think you can get a better source of randomness than Ruby's default, Ruby lets you provide it.

High-quality randomness is important to security; it's used in choosing encryption keys, for example. It's also the territory of experts. I've heard of people using the timing of packets, radio static, lava lamp movement, radioactive decay, or some combination thereof to seed their random number generators.

Personally, I'm just happy that I can make a randomly-behaving program settle down for a minute and behave predictably.