1 %%
2 %% %CopyrightBegin%
3 %%
4 %% Copyright Ericsson AB 1996-2011. All Rights Reserved.
5 %%
6 %% The contents of this file are subject to the Erlang Public License,
7 %% Version 1.1, (the "License"); you may not use this file except in
8 %% compliance with the License. You should have received a copy of the
9 %% Erlang Public License along with this software. If not, it can be
10 %% retrieved online at http://www.erlang.org/.
11 %%
12 %% Software distributed under the License is distributed on an "AS IS"
13 %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14 %% the License for the specific language governing rights and limitations
15 %% under the License.
16 %%
17 %% %CopyrightEnd%
18 %%
19 -module(random).
20
21 %% Reasonable random number generator.
22 %% The method is attributed to B. A. Wichmann and I. D. Hill
23 %% See "An efficient and portable pseudo-random number generator",
24 %% Journal of Applied Statistics. AS183. 1982. Also Byte March 1987.
25
26 -export([seed/0, seed/1, seed/3, uniform/0, uniform/1,
27 uniform_s/1, uniform_s/2, seed0/0]).
28
29 -define(PRIME1, 30269).
30 -define(PRIME2, 30307).
31 -define(PRIME3, 30323).
32
33 %%-----------------------------------------------------------------------
34 %% The type of the state
35
36 -type ran() :: {integer(), integer(), integer()}.
37
38 %%-----------------------------------------------------------------------
39
40 -spec seed0() -> ran().
41
42 seed0() ->
43 {3172, 9814, 20125}.
44
45 %% seed()
46 %% Seed random number generation with default values
47
48 -spec seed() -> ran().
49
50 seed() ->
51 case seed_put(seed0()) of
52 undefined -> seed0();
53 {_,_,_} = Tuple -> Tuple
54 end.
55
56
57 %% seed({A1, A2, A3})
58 %% Seed random number generation
59
60 -spec seed({A1, A2, A3}) -> 'undefined' | ran() when
61 A1 :: integer(),
62 A2 :: integer(),
63 A3 :: integer().
64
65 seed({A1, A2, A3}) ->
66 seed(A1, A2, A3).
67
68 %% seed(A1, A2, A3)
69 %% Seed random number generation
70
71 -spec seed(A1, A2, A3) -> 'undefined' | ran() when
72 A1 :: integer(),
73 A2 :: integer(),
74 A3 :: integer().
75
76 seed(A1, A2, A3) ->
77 seed_put({(abs(A1) rem (?PRIME1-1)) + 1, % Avoid seed numbers that are
78 (abs(A2) rem (?PRIME2-1)) + 1, % even divisors of the
79 (abs(A3) rem (?PRIME3-1)) + 1}). % corresponding primes.
80
81
82 -spec seed_put(ran()) -> 'undefined' | ran().
83
84 seed_put(Seed) ->
85 put(random_seed, Seed).
86
87 %% uniform()
88 %% Returns a random float between 0 and 1.
89
90 -spec uniform() -> float().
91
92 uniform() ->
93 {A1, A2, A3} = case get(random_seed) of
94 undefined -> seed0();
95 Tuple -> Tuple
96 end,
97 B1 = (A1*171) rem ?PRIME1,
98 B2 = (A2*172) rem ?PRIME2,
99 B3 = (A3*170) rem ?PRIME3,
100 put(random_seed, {B1,B2,B3}),
101 R = B1/?PRIME1 + B2/?PRIME2 + B3/?PRIME3,
102 R - trunc(R).
103
104 %% uniform(N) -> I
105 %% Given an integer N >= 1, uniform(N) returns a random integer
106 %% between 1 and N.
107
108 -spec uniform(N) -> pos_integer() when
109 N :: pos_integer().
110
111 uniform(N) when is_integer(N), N >= 1 ->
112 trunc(uniform() * N) + 1.
113
114
115 %%% Functional versions
116
117 %% uniform_s(State) -> {F, NewState}
118 %% Returns a random float between 0 and 1.
119
120 -spec uniform_s(State0) -> {float(), State1} when
121 State0 :: ran(),
122 State1 :: ran().
123
124 uniform_s({A1, A2, A3}) ->
125 B1 = (A1*171) rem ?PRIME1,
126 B2 = (A2*172) rem ?PRIME2,
127 B3 = (A3*170) rem ?PRIME3,
128 R = B1/?PRIME1 + B2/?PRIME2 + B3/?PRIME3,
129 {R - trunc(R), {B1,B2,B3}}.
130
131 %% uniform_s(N, State) -> {I, NewState}
132 %% Given an integer N >= 1, uniform(N) returns a random integer
133 %% between 1 and N.
134
135 -spec uniform_s(N, State0) -> {integer(), State1} when
136 N :: pos_integer(),
137 State0 :: ran(),
138 State1 :: ran().
139
140 uniform_s(N, State0) when is_integer(N), N >= 1 ->
141 {F, State1} = uniform_s(State0),
142 {trunc(F * N) + 1, State1}.