Tracks
/
Elixir
Elixir
/
Syllabus
/
Randomness
Ra

Randomness in Elixir

3 exercises

About Randomness

In Elixir, to choose a random element from an enumerable data structure (e.g. list, range), we use Enum.random/1. This function will pick a single element, with every element having equal probability of being picked. Picking a single random value from a range is executed in constant time, without traversing the whole range.

Random integers and letters

  • Choosing a random integer
    Enum.random(1..10)
    # => 7
    
  • Choosing a random letter as a string
    <<Enum.random(?A..?Z)>>
    # => "K"
    
  • Choosing a random letter as a charlist
    [Enum.random(?A..?Z)]
    # => ~c"J"
    

To choose more than one element from an enumerable data structure, use Enum.take_random/2. To sort an enumerable data structure in a random order, use Enum.shuffle/1.

Random floats

Elixir does not have its own functions for picking a random float. To do that, we have to use Erlang's rand module, which also happens to be what Enum.random uses under the hood.

  • Choosing a random float (equal to or greater than 0.0 and less than 1.0):

    :rand.uniform()
    # => 0.275329955448815
    
  • Choosing a random float (equal to or greater than a and less than b):

    a = 13
    b = 20
    :rand.uniform() * (b - a) + a
    # => 18.96815556890448
    

Normal distribution

All the functions mentioned above choose a random value with every possible value having the same probability of being chosen. That's called a uniform distribution. The rand module also offers normal/0 and normal/2 functions that choose a random float with a normal distribution.

Seed

It's important to understand that the "random" values are generated by a pseudo random number generator. A PRNG is an algorithm that, given an initial value called a seed, will generate a sequence of numbers that seems random, but isn't random at all.

This fact might be useful for debugging. You can force Erlang's (and thus Elixir's) pseudo random number generator to produce the same sequence values by resetting its seed using :rand.seed/2. The first argument is a specific PRNG algorithm, and the second a three-integer-tuple - the seed.

:rand.seed(:exsss, {1, 2, 3})
Enum.take_random(100..999, 3)
# => [680, 127, 622]

:rand.seed(:exsss, {1, 2, 3})
Enum.take_random(100..999, 3)
# => [680, 127, 622]

Cryptography

The random values returned by Enum.random and the Erlang's rand module are not cryptographically secure. Do not use them to generate cryptographical keys, passwords, or nonces. For this use case, there's Erlang's :crypto.strong_rand_bytes/1.

Edit via GitHub The link opens in a new window or tab

Learn Randomness

Practicing is locked

Unlock 2 more exercises to practice Randomness