每次調用會更新進程字典里的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}.
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,后面根據其業務規則,生成隨機數.
