首页 > 技术文章 > erlang的随机数 及 random:uniform()函数

unqiang 2014-12-23 18:56 原文

  每次调用会更新进程字典里的random_seed变量,这样在同一个进程内每次调用random:uniform()时,随机数种子都不同,所以生成的随机数都不一样(调用完random:uniform()后,可以用get(random_seed)查看更新后的种子值)。

但是如果是不同的进程分别调用random:uniform(),因为随机种子更新的算法是一样的,所以每次各进程的随机数种子也是相同的,从而生成的随机数也是一样的,要想让不同进程生成的随机数不同,要手动为每个进程设置不同的种子,常用的是用erlang:now,比如:

random:seed(erlang:now()),random:uniform().

不过如果每个进程调用random:seed(erlang:now())太接近,种子值会比较接近,生成的随机数也会比较接近,更好的方法是用一个单独的进程来生成种子,保证每次的种子值相差比较大

Seed = {random:uniform(99999), random:uniform(999999), random:uniform(999999)}

然后每次调用random:uniform()前从该种子生成进程获取最新的种子值,seed()之。

 

下面为random.erl 的源码:

  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}.
View Code

 random:seed 由进程字典put存了随机数,random:uniform则get取了随机数,而它同时又put了新的随机数.

 

如果一开始直接调用,random:uniform/0,  则一开始 get(random_seed)为undefined,后面每次生产的种子的规则都是根据其业务规则生成。 但如果是 先调用random:seed/1 ,则它先生成了随机种子,put到random_seed 的进程字典中,后面依次调用random:uniform/0的时候,则从random_seed的进程字典中取出随机种子,则不是undefined,后面根据其业务规则,生成随机数.

推荐阅读