2009-06-10 10 views
5

필자는 실행 당 의사 난수 생성기를 두 번 이상 시드하지 않았지만 철저한 설명은 절대로하지 않는 것이 좋습니다.의사 난수 생성기를 두 번 이상 시드하는 데 문제가 있습니까?

int get_rand() { 
    srand(time(NULL)); 
    return rand(); 
} 

초 당 get_rand 여러 번 호출하기 때문에 결과를 반복 생성합니다 물론, 다음 (C/C++) 예를 들어 좋은 생각이 아닌 이유를 쉽게 알 수있다.

그러나 다음 예는 여전히 받아 들일만한 해결책이 아닙니까?

MyRand.h

#ifndef MY_RAND_H 
#define MY_RAND_H 

class MyRand 
{ 
    public: 
    MyRand(); 
    int get_rand() const; 
    private: 
    static unsigned int seed_base; 
}; 

#endif 

MyRand.cpp

#include <ctime> 
#include <cstdlib> 
#include "MyRand.h" 

unsigned int MyRand::seed_base = static_cast<unsigned int>(time(NULL)); 

MyRand::MyRand() 
{ 
    srand(seed_base++); 
} 

int MyRand::get_rand() const 
{ 
    return rand(); 
} 

MAIN.CPP

#include <iostream> 
#include "MyRand.h" 

int main(int argc, char *argv[]) 
{ 
    for (int i = 0; i < 100; i++) 
    { 
    MyRand r; 
    std::cout << r.get_rand() << " "; 
    } 
} 

MyRand : 생성자가 빠르게 연속적으로 여러 번 호출 되더라도 srand을 호출 할 때마다 다른 매개 변수가 있습니다. 분명히 이것은 스레드로부터 안전하지는 않지만 다시는 rand이 아닙니다.

+0

이 연습의 목적은 'MyRand'의 클라이언트에서 srand를 호출하는 "부담"을 덜어주는 것입니다. 여기서 MyRand는 다이를 모델링하는 것일 수 있습니다. 그러나 반면에, 우리가 같은 방법으로 재산 바퀴, 동전 던지기 등을 구축한다면, 우리는 많은 씨앗을 얻을 것이다. – a038c56f

답변

6

의사 랜덤 넘버 생성기 함수를 호출 할 때마다 생성기는 내부 상태를 취하여 의사 난수와 새 내부 상태를 생성합니다. 내부 상태를 변환하기위한 알고리즘은 신중하게 선택되어 출력이 무작위로 나타납니다.

난수 생성기를 시드하면 기본적으로이 내부 상태가 설정됩니다. 내부 상태를 예측 가능한 값으로 재설정하면 임의성이 사라집니다.

예를 들어, 인기있는 단순한 RNG는 선형 합동 생성기입니다. 숫자는 다음과 같이 생성됩니다.

X[n+1] = (a X[n] + c) mod m 

이 경우 X [n + 1]은 결과와 새 내부 상태입니다.위의 제안대로 발전기마다 종자 경우는 다음과 같습니다 시퀀스를 얻을 것이다 : b는 당신의 seed_base입니다

{(ab + c) mod m, (a(b+1) + c) mod m, (a(b+2) + c) mod m, ...} 

. 이것은 전혀 임의적으로 보이지 않습니다.

+0

제 main.cpp 예제는 첫 번째 예제의 결함이 없음을 입증하기 위해 다소 과장되었습니다. 'get_rand'를 호출 할 때마다 새로운 객체를 인스턴스화하면 위에서 설명한 상황이 발생하지만 이는 낭비적인 프로그래밍 일뿐입니다. 'MyRand' 인스턴스 생성의 수가'get_rand' 호출에 비해 적은 것으로 가정하면, 상황이 좀 나아질 것입니다. – a038c56f

1

시드를 예측할 수 있습니다. 시드가 예측 가능하기 때문에 증가하는 바로 이후로 여기에 표시됩니다. rand()의 결과도 예측 가능합니다.

정말 난수를 생성하려는 이유와 "임의"가 허용되는 임의의 난수에 따라 달라집니다. 귀하의 예에서, 그것은 연속적으로 중복을 피할 수 있으며, 그것은 당신에게 충분할 수 있습니다. 결국 중요한 것은 그것이 실행된다는 것입니다.

거의 모든 플랫폼에 rand()보다 난수를 생성하는 더 좋은 방법이 있습니다.

1

잘 수행 할 필요가없는 추가 처리입니다.

이 시나리오에서는 루프의 시작 전에 시간 기반 시드로 한 번만 생성자를 호출합니다. 그러면 모든 반복에 대해 시드를 변경해야하는 추가 오버 헤드없이 임의의 결과가 보장됩니다.

나는 당신의 방법이 더 이상 이상이라고 생각하지 않을 것입니다.

0

난수 생성을 생각해 볼 수 있습니다 (이는 더 엄격한 구현 일뿐만 아니라 더 이상 설명이 아닙니다.). 간단한 무작위 샘플을 수행하는 통계에서이 작업을 수행 한 것을 기억하면 씨앗은 기본적으로 큰 숫자의 임의의 숫자에서 시작할 행과 열을 알려줍니다. 우리가 이미 숫자가 정상적으로 이미 분포되어 있다고 가정 할 수 있기 때문에 반복적으로 재사용하는 것은 단순히 불필요합니다.

시드를 두 번 이상 추가하면 응용 프로그램에 따라 충분하기 때문에 시드를 두 번 이상 추가 할 경우 이점이 없습니다. "더 많은"난수가 필요하다면 난수 생성 방법이 많이 있습니다. 내가 생각할 수있는 한 가지 경우는 스레드로부터 안전한 방식으로 난수를 생성하는 것입니다.

당신의 해결책은 받아 들일 수 있지만, 당신의 숫자는 전 세계적으로 한번 시드하는 것보다 더 이상 무작위 적이 지 않을 것입니다. srand는 일반적으로 생성자에 속해서는 안됩니다. 난수를 지원하려면 프로그램이 시작될 때 한 번 시드하고 잊어 버리십시오.