Ruby has a `Random`

class that can generate pseudo-random numbers. The reason for ** pseudo** is that it produces a deterministic sequence of bits which approximate true randomness. You can generate integers, floats, and even binary strings.

I've always found myself referring to the docs to understand various ways Ruby lets you generate random numbers and thought it'd be nice to write a cookbook-style post listing the important recipes. So here it goes.

## Random Number Generation in Ruby

The simplest way to generate random numbers in Ruby is to use the `Kernel#rand`

method.

```
rand # 0.47578359467975184
rand 10 # 2
rand 4.5 # 3
rand 1.2..3.5 # 3.3037237197517415
rand 5...8 # 6
```

**What do all these arguments mean?** Let's study the `Random`

class for a deeper investigation, since the `Random::rand`

class method works similarly to the `Kernel#rand`

method, returning a random number based on the argument.

There are three different versions of this method.

- Calling
`Random.rand`

without providing any arguments will return a random float number between 0 and 1 (not including 1).

`Random.rand # 0.8722060064922107`

- Calling
`Random.rand(max)`

by providing the max value will generate a random number between 0 and`max`

(but not including`max`

).

```
Random.rand(10) # 7
Random.rand(10) # 3
Random.rand(14) # 2
Random.rand(1.5) # 0.008421002905374453
```

- Calling
`Random.rand(Range)`

with a Range will generate a random number within that range. If you use`..`

, the range will include the end value, and if you use`...`

, it will exclude the end value.

```
# can generate 2, 3, or 4
Random.rand(2..4) # 3
# can generate 2 or 3
Random.rand(2...4) # 2
# A float range
Random.rand(2.1...4.4) # 2.35435574571588
```

The same method is also available on an instance of `Random`

, so you could do `Random.new.rand(5)`

and so on.

**Should You Use **Random** or **Random.new**?**

To be honest, I don't know. While researching for this post, I came across this excellent answer on Stack Overflow from Marc-André Lafortune:

In most cases, the simplest is to use`rand`

or`Random.rand`

.

Creating a new random generator each time you want a random number is areally bad idea. If you do this, you will get the random properties of the initial seeding algorithm which are atrocious compared to the properties of the random generator itself.

- Stack Overflow

He goes on to suggest:

If you use`Random.new`

, you should thus call itas rarely as possible, for example once as`MyApp::Random = Random.new`

and use it everywhere else.

Sound advice.

The next day, right before I was going to publish this post, I stumbled across this post on Stack Overflow, where Schwern suggests the exact opposite approach:

`Random.new.rand`

is better than`rand`

because each separate instance of`Random`

will be using a different seed (and thus a different psuedo-random pattern), whereas every call to`rand`

is using the same seed.

If your code is using`rand`

to generate random numbers, the attacker can assume that any random number is using the same seed and the same sequence. Then they can more quickly gather observations to guess at the seed.

If each part of your code is using its own`Random.new`

, now the attacker has to figure out which random number goes with which seed. This makes it harder to build a sequence of random numbers, and gives the attacker less numbers to work with.

- Stack Overflow

Which also sounds like a good advice. From the profiles of both Marc and Schwern, it seems like they both know what they're talking about. So I'm confused. **Is there a consensus or best practice to choose one or the other?**

To get some clarity, I posted a question on the Ruby Subreddit, but the answers were... unsatisfactory?

Anyway, let's continue!

## How to Generate Secure Random Numbers?

Often you may need to generate secure random numbers which are useful for generating session keys in HTTP cookies.

While the `Random`

class is suitable for many scenarios, it is not recommended for situations where cryptographic security is a concern, as the predictability of pseudo-random number generators makes them vulnerable to certain types of attacks.

To generate secure random numbers, use the ``securerandom``

gem (make sure to install the gem first with `gem install securerandom`

).

```
require "securerandom"
SecureRandom.alphanumeric # "tpEnoWgScSJRU3YB"
SecureRandom.base64 # "0jHnJ7Yx5oTW0OY+YKgUog=="
SecureRandom.hex # "b51372ee8b93eb3e1f0035d9300c3e97"
SecureRandom.rand # 0.6053942880507039
SecureRandom.urlsafe_base64 # "OTHNscnomrNjjT0g_dzpdw"
SecureRandom.uuid # "f6f54bd8-fc5a-483f-8909-05428dea2290"
```

The numbers generated by `SecureRandom`

are not easily predictable, even if an attacker knows previous values generated.

Check out the documentation to learn more.

## How to Generate a Random Binary String in Ruby?

The `bytes(size)`

class method returns a random binary string. To control the length of the generated string, use the `size`

argument.

```
Random.bytes(5) # "\xFFT\f\xE0\x0F"
Random.bytes(10) # ":\x84q>\xD1\x15G\xBA\xAA\xF4"
```

If you don't provide the size, Ruby will throw an error.

`bytes`

is also available as an instance method.

`Random.new.bytes(8) # "\xF0j\xFBa\xCC\x1C\xCF\x12"`

## How to Get the seed value used to generate an instance of random generator?

Use the `seed`

class method to get the seed value used to initialize the random generator. This is useful if you want to initialize another random number generator with the same state as the first, at a later time.

```
Random.seed #=> 1234
prng1 = Random.new(Random.seed)
prng1.seed #=> 1234
prng1.rand(100) #=> 47
Random.rand(100) #=> 47
```

The second generator will provide the same sequence of numbers.

## How to Generate Random Numbers in Pre-Defined Formats?

The `Random::Formatter`

module formates generated random numbers in many manners. To use it, simply require it. It makes several methods available as Random's instance as well as module methods.

```
require "random/formatter"
Random.hex # "1aed0c631e41be7f77365415541052ee"
Random.base64(4) # "bsQ3fQ=="
Random.alphanumeric # "TmP9OsJHJLtaZYhP"
Random.uuid # "f14e0271-de96-45cc-8911-8910292a42cd"
```

For a complete reference, check out the documentation of the `Random::Formatter`

.

## How to Initialize Random Class with Seed Values?

To initialize the `Random`

class, you can provide a seed value. You can use the `Kernel#srand`

method to generate this seed, or can manually supply one.

`srand`

may be used to ensure repeatable sequences of pseudo-random numbers between different runs of the program. This is helpful in testing. You can make your tests deterministic by setting the seed to a known value.

```
srand 1234 # seed with 1234
[ rand, rand ] # => [0.1915194503788923, 0.6221087710398319]
srand 1234 # seed with 1234
[ rand, rand ] # => [0.1915194503788923, 0.6221087710398319]
srand 5678 # seed with 5678
[ rand, rand ] # => [0.4893269800108977, 0.05933244265166393]
```

An important thing to keep in mind is that the random number generator becomes deterministic if you use the same seed value. That is, different instances will return the same values.

```
r1 = Random.new(1234)
r1.rand # 0.1915194503788923
r1.rand # 0.6221087710398319
r2 = Random.new(1234)
r2.rand # 0.1915194503788923
r2.rand # 0.6221087710398319
```

When you don't provide a seed value, Ruby uses an arbitrary seed value generated by the `new_seed`

class method.

```
Random.new_seed # 281953773930427386731290692710425966835
Random.new_seed # 105614143647114073473001171940625552466
```

Since Ruby takes care of using a new seed value each time, I suggest you initialize the `Random`

instances without providing an explicit seed value.

That's a wrap. I hope you found this article helpful and you learned something new.

As always, if you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I reply to all emails I get from developers, and I look forward to hearing from you.

If you'd like to receive future articles directly in your email, please subscribe to my blog. If you're already a subscriber, thank you.