Erlang Central

Difference between revisions of "Random Numbers"

From ErlangCentral Wiki

m (random:uniform/1 never returns 0)
(One intermediate revision by one user not shown)
Line 5:Line 5:
 
== Solution ==
 
== Solution ==
  
Use random:uniform function from the standard Erlang distribution. It has two forms: (1) a no-argument version that returns a random float value in the range of 0.0 to 1.0, and (2) an version that takes a single integer (N) and returns a random integer in the range of 1 to N.  
+
Use random:uniform/0 and random:uniform/1 ; the first returns a random float uniformly distributed between [0.0,1.1], and the second returns a random integer uniformly distributed between [1,N].
 
<code>
 
<code>
 
1> random:uniform().
 
1> random:uniform().
9.23009e-2
+
0.159112
 
2> random:uniform(150).
 
2> random:uniform(150).
 
67
 
67
 
</code>
 
</code>
  
This code generates and prints a random integer between 25 and 75, inclusive:
+
To select random integers from [N,M], can use N+random:uniform(M-N).
<code>
+
3> io:fwrite("Random = ~B\n", [random:uniform(51) + 24]).
+
Random = 74
+
ok
+
</code>
+
 
+
In the example, we want to limit the range to 25 to 75, so we add 24 to the result of the random:uniform function. This means we really want a random number between 1 and 51, so we give the random:uniform function the argument 51 (since the generated number is always from 1 to N).
+
 
+
The canonical application for this kind of number generation is the random selection of an element from a vector:
+
<code>
+
4> Dict = dict:from_list([{1,$a}, {2,$b}, {3,$c}, {4,$d}, {5,$1},
+
4>  {6,$2}, {7,$3}]).                                           
+
{dict,7,
+
      16,
+
      16,
+
      8,
+
      80,
+
      48,
+
      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},
+
      {{[],
+
        [[3|99]],
+
        [[6|50]],
+
        [],
+
        [],
+
        [],
+
        [[2|98]],
+
        [[5|49]],
+
        [],
+
        [],
+
        [],
+
        [[1|97]],
+
        [[4|100]],
+
        [[7|51]],
+
        [],
+
        []}}}
+
5> dict:fetch(random:uniform(7), Dict).
+
100
+
6> io:fwrite("~c\n", [100]).
+
d
+
ok
+
</code>
+
  
Another common example is generating a random password:  
+
A common example is generating a random password:  
 
<code>
 
<code>
generate_8_password() ->
+
generate_password(N) ->
     lists:flatten(lists:foldl(fun(X,AccIn) ->
+
     lists:map(fun (_) -> random:uniform(90)+$\s+1 end, lists:seq(1,N)).
        [random:uniform(90) + 32|AccIn] end,
+
        [], lists:seq(1,8))).
+
  
7> generate_8_password().
+
3> generate_password(8).
"]VD'hEa;"
+
"l?8j#$&&"
8> generate_8_password().
+
4> generate_password(8).
"Zju!W9'Z"
+
"V<bFi(EW"
9> generate_8_password().
+
5> generate_password(8).
"uw6uX\"JF"
+
"irp^DXTz"
10> generate_8_password().
+
"-)3Ue=8n"
+
 
</code>
 
</code>
  

Revision as of 07:32, 24 March 2009

Problem

You want a random number from a given range. For example, you wish to randomly select one element from an array, simulate rolling a die in a game of chance, or generate a random password.

Solution

Use random:uniform/0 and random:uniform/1 ; the first returns a random float uniformly distributed between [0.0,1.1], and the second returns a random integer uniformly distributed between [1,N].

1> random:uniform().
0.159112
2> random:uniform(150).
67

To select random integers from [N,M], can use N+random:uniform(M-N).

A common example is generating a random password:

generate_password(N) ->
    lists:map(fun (_) -> random:uniform(90)+$\s+1 end, lists:seq(1,N)).

3> generate_password(8).
"l?8j#$&&"
4> generate_password(8).
"V<bFi(EW"
5> generate_password(8).
"irp^DXTz"

The Erlang random number generator is attributed to B.A. Wichmann and I.D.Hill, in 'An efficient and portable pseudo-random number generator', Journal of Applied Statistics. AS183. 1982. Also Byte March 1987.

It can support bigint values, so no special recipe is required for extremely large random numbers.