Lee
Lee

Reputation: 31070

List handling and random number generation in Erlang

Why do I get a list of identical numbers when I run randy:spawner() below? I was expecting a list of random numbers. How could I change the code to achieve this?

-module(randy).
-export([randlister/2,spawner/0]).
-import(lists,[map/2]).

spawner() ->
    [spawn(fun() -> randlister(X,random:uniform()) end) || X <- lists:seq(1,3)].


randlister(X, Randomnumber) ->
io:format("~p,    ~p~n",[X,Randomnumber]).

Example output:

18> randy:spawner().
1,    0.4435846174457203
2,    0.4435846174457203
3,    0.4435846174457203

Upvotes: 0

Views: 584

Answers (2)

Xiao Jia
Xiao Jia

Reputation: 4269

Why do I get a list of identical numbers when I run randy:spawner() below?

You must seed before generating random numbers. Random number sequences generated from the same seed will be exactly the same.

If a process calls uniform/0 or uniform/1 without setting a seed first, seed/0 is called automatically. seed/0 will seed random number generation with a default (fixed) value, which can be accessed through seed0/0. On my laptop it always returns {3172,9814,20125} with a default process dictionary.

How could I change the code to achieve this?

In the simplest case, the solution from @EmilVikström is sufficient. However, I do recommend to keep track of the random number generation state so you can have a easier life when you're debugging.

A random number generation state is just a 3-tuple of integers, as returned by now(). The seed is just the first state. Then you can use uniform_s/1 or uniform_s/2 to generate random numbers from specified states.

By using these functions with states, you can specify random number seeds outside your Erlang code, e.g. passing a seed through command-line options or environment variables.

  • When you are testing/debugging, fix the seed so that each time you run your program will give the same result.
  • When you are satisfied, change the seed in order to (probably) continue debugging :-)
  • When you are ready for production, just pass the current time (or whatever) as the seed, so you can have some randomness.

Upvotes: 2

Emil Vikstr&#246;m
Emil Vikstr&#246;m

Reputation: 91983

You must seed the random number generator in each process:

spawner() ->
    [spawn(fun() ->
                   random:seed(now()),
                   randlister(X,random:uniform())
           end) || X <- lists:seq(1,3)].

Upvotes: 5

Related Questions