Erlang :random.uniform

I’m building a simple project in Elixir which requires generating a random number (the number represents the roll of a die). Doing a cursory Google search on the proper way to generate a random number led me to using Erlang’s :rand module. As a side note, Elixir runs on the Erlang VM, which gives Elixir access to the entire Erlang ecosystem. Elixir code can invoke Erlang functions with no runtime cost.

As you can see, the linked SO post suggested :rand.uniform/1 to generate a random integer. I plugged in the suggested function, ran the function, and checked the output. Sure enough, there were my random numbers 3 and 5 (the function made two dice rolls). I ran the function again to verify the random integer generation and weirdly got the same result, 3 and 5. Running the function a third time, and a fourth time, and a fifth time all ended with the same output: 3 and 5. Very weird.

I then added in a throwaway line generating a random number before the dice roll generation, and the output was 5 and 6, which implied that the 3 was thrown away. Next, I fired up iex, Elixir’s REPL (or more precisely, a shell), and used the same random function. Lo and behold, 3 for the first execution and 5 for the second execution. What was going on?

Based on the chapter of Function Programming in Scala about creating the Random Number Generator, and its explanation that RNGs are often pseudo-random and are deterministic based on the initial seed (or more generally, based on the previous state), it seems probable that the same initial seed gets used by default whenever the Erlang VM is being initialized. That means that the dice rolls generated by my program would end up following the same pattern, which was not what I wanted (or what anyone wants when they reach for a random integer).

I also realized that I made a silly mistake. The SO answer that I linked to suggested using :rand.uniform/1. However, I typed :random.uniform/1. Apparently, both :random and :rand are Erlang modules that generate random numbers. The Erlang docs for :random suggest that one uses “the improved rand module” instead of using :random, so looks like my typo, while valid, chose the worse version of the two. And what do you know – swapping in :rand.uniform/1 for :random.uniform/1 actually produced different random numbers! The first four iterations resulted in [6, 1], [4, 4], [1, 4], and [6, 5].