为什么需要在 Matlab 中调用 rng() 两次
Why is it necessary to call rng() twice in Matlab
这对我来说似乎是一个错误。似乎有必要在 Matlab 中调用 rng()
两次以获得所需的播种。考虑以下实验:
>> sd = rng(3) % THIS DOES NOT WORK
sd =
Type: 'twister'
Seed: 0
State: [625x1 uint32]
>> sd = rng(3) % BUT NOW IT DOES
sd =
Type: 'twister'
Seed: 3
State: [625x1 uint32]
>> sd = rng(3) % AND AGAIN, TO CONFIRM
sd =
Type: 'twister'
Seed: 3
State: [625x1 uint32]
>> sd = rng('shuffle') % BUT THIS FAILS
sd =
Type: 'twister'
Seed: 3
State: [625x1 uint32]
>> sd = rng('shuffle') % BUT ON THE SECOND GO IT WORKS
sd =
Type: 'twister'
Seed: 87326715
State: [625x1 uint32]
>> sd = rng('shuffle') % AND ON THE THIRD
sd =
Type: 'twister'
Seed: 87326802
State: [625x1 uint32]
>> sd = rng(4) % BUT AGAIN THIS FAILS
sd =
Type: 'twister'
Seed: 87326987
State: [625x1 uint32]
>> sd = rng(4) % BUT ON THE SECOND GO IT WORKS AGAIN
sd =
Type: 'twister'
Seed: 4
State: [625x1 uint32]
>> sd = rng(4) % AND SO ON
sd =
Type: 'twister'
Seed: 4
State: [625x1 uint32]
简答:
根据文档,rng
的 return 值为 previous state:
sprev = rng(...) returns the previous settings of the random number
generator used by rand, randi,and randn before changing the settings.
所以,答案是:不,这不是错误。随机数生成器在您第一次调用时已正确初始化。
然而,在我看来,这是一个非常出乎意料的行为。
答案有点长:
我建议改用 RandStream
对象,对于具有面向对象编程基础知识的人来说,这更容易理解。例如:
s1 = RandStream.create('mrg32k3a');
r1 = rand(s1,100000,1);
我强烈建议避免设置全局流,因为它具有全局变量的所有缺点。
%Not recommended! (Due to global variable)
s = RandStream('mt19937ar','Seed',1);
RandStream.setGlobalStream(s);
编辑 (1)
我想解释一下为什么设置全局随机数生成器不是一个好的做法。基本上,任何好的软件的目的都是缩小任何变量的范围,以便reduce coupling and increase cohesion。全局变量具有最高可能的耦合(任何例程都可以使用它)和最低可能的内聚。全局随机数生成器甚至比普通变量 更具 风险,因为它有更多机会被其他人使用。
重新播种全局随机数生成器可能会导致一些奇怪的错误。考虑以下示例 - 您正在编写一个在 for
循环中运行并生成随机数的程序。
for i=1:N
k = randn(1,1);
%... Do something
end
一切似乎都很完美。现在你想在你的循环中间添加一个第三方函数 Foo
来做一些事情。代码的设计者决定将全局数字生成器重新播种到 1
.
for i=1:N
k = randn(1,1);
%... Do something
Foo();
end
function Foo()
%Do some stuff
rng(1);
end
惊喜!现在你的程序生成了一个完全非随机的数字序列,即在每个循环调用中完全相同的数字。
这对我来说似乎是一个错误。似乎有必要在 Matlab 中调用 rng()
两次以获得所需的播种。考虑以下实验:
>> sd = rng(3) % THIS DOES NOT WORK
sd =
Type: 'twister'
Seed: 0
State: [625x1 uint32]
>> sd = rng(3) % BUT NOW IT DOES
sd =
Type: 'twister'
Seed: 3
State: [625x1 uint32]
>> sd = rng(3) % AND AGAIN, TO CONFIRM
sd =
Type: 'twister'
Seed: 3
State: [625x1 uint32]
>> sd = rng('shuffle') % BUT THIS FAILS
sd =
Type: 'twister'
Seed: 3
State: [625x1 uint32]
>> sd = rng('shuffle') % BUT ON THE SECOND GO IT WORKS
sd =
Type: 'twister'
Seed: 87326715
State: [625x1 uint32]
>> sd = rng('shuffle') % AND ON THE THIRD
sd =
Type: 'twister'
Seed: 87326802
State: [625x1 uint32]
>> sd = rng(4) % BUT AGAIN THIS FAILS
sd =
Type: 'twister'
Seed: 87326987
State: [625x1 uint32]
>> sd = rng(4) % BUT ON THE SECOND GO IT WORKS AGAIN
sd =
Type: 'twister'
Seed: 4
State: [625x1 uint32]
>> sd = rng(4) % AND SO ON
sd =
Type: 'twister'
Seed: 4
State: [625x1 uint32]
简答:
根据文档,rng
的 return 值为 previous state:
sprev = rng(...) returns the previous settings of the random number generator used by rand, randi,and randn before changing the settings.
所以,答案是:不,这不是错误。随机数生成器在您第一次调用时已正确初始化。
然而,在我看来,这是一个非常出乎意料的行为。
答案有点长:
我建议改用 RandStream
对象,对于具有面向对象编程基础知识的人来说,这更容易理解。例如:
s1 = RandStream.create('mrg32k3a');
r1 = rand(s1,100000,1);
我强烈建议避免设置全局流,因为它具有全局变量的所有缺点。
%Not recommended! (Due to global variable)
s = RandStream('mt19937ar','Seed',1);
RandStream.setGlobalStream(s);
编辑 (1) 我想解释一下为什么设置全局随机数生成器不是一个好的做法。基本上,任何好的软件的目的都是缩小任何变量的范围,以便reduce coupling and increase cohesion。全局变量具有最高可能的耦合(任何例程都可以使用它)和最低可能的内聚。全局随机数生成器甚至比普通变量 更具 风险,因为它有更多机会被其他人使用。
重新播种全局随机数生成器可能会导致一些奇怪的错误。考虑以下示例 - 您正在编写一个在 for
循环中运行并生成随机数的程序。
for i=1:N
k = randn(1,1);
%... Do something
end
一切似乎都很完美。现在你想在你的循环中间添加一个第三方函数 Foo
来做一些事情。代码的设计者决定将全局数字生成器重新播种到 1
.
for i=1:N
k = randn(1,1);
%... Do something
Foo();
end
function Foo()
%Do some stuff
rng(1);
end
惊喜!现在你的程序生成了一个完全非随机的数字序列,即在每个循环调用中完全相同的数字。