2015-01-06 4 views
3

이것은 나에게 버그처럼 보입니다. 원하는 시딩을 얻으려면 Matlab에서 rng()을 두 번 호출해야합니다. 다음과 같은 실험을 고려해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] 

답변

5

짧은 답변 :

sprev = RNG (...)가를 반환 를 문서에 따르면, rng의 반환 값은 이전 상태가 설정을 변경하기 전에 랜덤 번호 생성기가 이전의 rand, randi 및 randn 생성기에서 사용한 설정.

따라서 대답은 아니요,이 아닙니다. 난수 생성기는 처음 호출 할 때 올바르게 초기화되었습니다.

그러나 제 생각에는 예상치 못한 동작입니다.


조금 더 대답 : 내가 훨씬 더 쉽게 객체 지향 프로그래밍에 대한 기본적인 지식을 가진 사람에 대해 이해할 수 있습니다 대신 RandStream 개체를 사용하는 것이 좋습니다. 예를 들면 다음과 같습니다.

글로벌 스트림의 모든 단점을 가지고 있기 때문에 글로벌 스트림을 설정하지 않는 것이 좋습니다.

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

편집 (1) I 글로벌 난수 발생기를 설정하는 이유에 대한 내 의견을 설명하고자 은 좋은 방법이 아닙니다. 기본적으로, 좋은 소프트웨어의 목적은 변수의 범위를 줄이기 위해서이며, 순서는 reduce coupling and increase cohesion입니다. 전역 변수는 가능한 가장 높은 결합 (모든 루틴에서 사용할 수 있음) 및 가능한 가장 낮은 결합을가집니다. 전역 난수 생성기는 다른 사람이 사용할 확률이 훨씬 높기 때문에 이상일 수도 있습니다.은 일반 변수보다 위험합니다.

글로벌 난수 생성 프로그램을 다시 시드하면 기괴한 오류가 발생할 수 있습니다. 다음 예를 생각해보십시오 - 루프를 실행하는 프로그램을 쓰고 있습니다. for과 난수를 생성합니다.

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

모든 것이 완벽하게 보입니다. 이제 루프의 중간에 제 3 자 함수 인 Foo을 추가하여 일부 작업을 수행하려고합니다. 코드 설계자는 글로벌 번호 생성기를 1으로 다시 시드하기로 결정했습니다.

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

function Foo() 
    %Do some stuff 
    rng(1); 
end 

놀람! 이제 프로그램은 숫자가 완전히 무작위 인 순서, 즉 각 루프 호출에서 정확히 동일한 숫자를 생성합니다. 당신은 여전히 ​​확신하지 않는 경우

좀 더 읽기 데이터는 - Here, herehere

+1

윽, 당신 말이 맞아. 또한 매우 예상치 못한 결과입니다.예를 들어,이 동작을 고려하십시오. 여기서'sd.Seed'는 3입니다 :'rng (3); sd = rng()'. 하지만 여기서'sd.Seed'는 이전 버전과 같을 것입니다.'sd = rng (3)' – Patrick

+2

@Andrey, 개발자들이 당신의 답을 읽을 때 울음 소리가 들립니다. 'rng' 명령어는 RandStream 기능의 단순화로 소개되었는데, 사용자가 알지 못한다면 사용자가 난수 스트림 내부에 간섭하는 것을 막기 위해 의도적으로 약간의 묘한 ("mrg32k3a"가 무엇인가?)으로 설계되었습니다. 정확히 무엇을하고 있었는지. 그리고 여기 당신은'rng'은 혼란 스럽지만'RandStream'은 이해하기 쉽다고 말합니다. 당신에 대한 비판은 아닙니다. 그러나 당신의 기대와 디자인의 차이는 아이러니합니다. –

+0

무엇? 그것은 글로벌 스트림에 대한 이상한 반대입니다. 만약 그것을 사용하기를 원치 않는다면, 전역 변수에 대한 일반적인 반대 때문이 아닐 것입니다. 또한 OP의 질문은 기본적으로 글로벌 스트림을 기반으로하는 'rng'에 관한 것입니다. – horchler

관련 문제