为什么有必要在Matlab中调用rng()两次

Pat*_*ick 3 random matlab

这对我来说似乎是个错误.似乎有必要rng()在Matlab中调用两次以获得所需的种子.考虑以下实验:

>> 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]
Run Code Online (Sandbox Code Playgroud)

And*_*ein 5

简短回答: 根据文档,返回值rng先前的状态:

sprev = rng(...)在更改设置之前返回rand,randi和randn使用的随机数生成器的先前设置.

所以,答案是:不,这不是一个bug.第一次调用时,随机数生成器已正确初始化.

但是,在我看来,这是一个非常意想不到的行为.


更长的答案: 我建议使用RandStream对象,对于具有面向对象编程基础知识的人来说,这更容易理解.例如:

s1 = RandStream.create('mrg32k3a');
r1 = rand(s1,100000,1);
Run Code Online (Sandbox Code Playgroud)

我强烈建议避免设置全局流,因为它具有全局变量的所有缺点.

%Not recommended! (Due to global variable)
s = RandStream('mt19937ar','Seed',1);
RandStream.setGlobalStream(s);
Run Code Online (Sandbox Code Playgroud)

编辑(1) 我想解释一下为什么设置全局随机数生成器不是一个好习惯.基本上,任何好软件的目的都是为了减少任何变量的范围,以减少耦合并增加内聚力.全局变量具有最高可能的耦合(任何例程可以使用它)和最低可能的内聚.全球随机数发生器甚至比正常的变量有风险的,因为它必须被别人使用更多的机会.

重新播种全局随机数生成器可能会导致一些奇怪的错误.请考虑以下示例 - 您正在编写一个在for循环中运行并生成随机数的程序.

 for i=1:N
     k = randn(1,1); 
     %... Do something
 end
Run Code Online (Sandbox Code Playgroud)

一切似乎都很完美.现在你想Foo在你的循环中添加一个第三方函数来做一些事情.代码的设计者决定将全局数字生成器重新种子化1.

 for i=1:N
     k = randn(1,1); 
     %... Do something
     Foo();
 end

 function Foo()
     %Do some stuff
     rng(1);
 end
Run Code Online (Sandbox Code Playgroud)

惊喜!现在,您的程序生成一个完全非随机的数字序列,即每个循环调用中的数字完全相同.

如果你仍然不相信,还有更多的阅读数据 - 这里,这里这里

  • @Andrey,我可以听到开发人员在阅读你的答案时哭了.`rng`命令是作为`RandStream`功能的_simplification_引入的,它被故意设计为有点神秘(什么是"mrg32k3a"?),以阻止用户干扰随机数流的内部,除非他们知道正是他们在做什么.在这里,你说'rng`令人困惑但是`RandStream`很容易理解.没有批评你 - 但你的期望和设计之间的差距是具有讽刺意味的. (2认同)