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