의사 난수 생성기를 두 번 이상 시드하는 데 문제가 있습니까?
문제
나는 실행당 의사 난수 생성기를 두 번 이상 시딩하지 말라는 권장 사항을 꽤 많이 보았지만 자세한 설명은 전혀 동반되지 않았습니다.물론 다음(C/C++) 예제가 좋은 생각이 아닌 이유를 쉽게 알 수 있습니다.
int get_rand() {
srand(time(NULL));
return rand();
}
전화한 이후로 get_rand
초당 여러 번 반복되는 결과가 생성됩니다.
하지만 다음 예는 여전히 수용 가능한 솔루션이 아닐까요?
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();
}
메인.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
:s 생성자는 빠르게 연속해서 여러 번 호출됩니다. srand
다른 매개변수가 있습니다.분명히 이것은 스레드로부터 안전하지 않지만 역시 마찬가지입니다. rand
.
해결책
의사 난수 생성기 함수를 호출할 때마다 생성기는 내부 상태를 취하고 의사 난수와 새로운 내부 상태를 생성합니다.내부 상태를 변환하는 알고리즘은 출력이 무작위로 나타나도록 신중하게 선택됩니다.
난수 생성기를 시드하면 기본적으로 이 내부 상태를 설정하게 됩니다.내부 상태를 예측 가능한 값으로 재설정하면 무작위성이 사라집니다.
예를 들어, 널리 사용되는 간단한 RNG는 선형 합동 생성기입니다.숫자는 다음과 같이 생성됩니다.
X[n+1] = (a X[n] + c) mod m
이 경우 X[n+1]은 결과이자 새로운 내부 상태입니다.위에서 제안한 대로 매번 생성기를 시드하면 다음과 같은 시퀀스를 얻게 됩니다.
{(ab + c) mod m, (a(b+1) + c) mod m, (a(b+2) + c) mod m, ...}
b는 어디 있어? seed_base
.이것은 전혀 무작위로 보이지 않습니다.
다른 팁
씨앗을 예측할 수있는 경우, 단지 여기에있는 이후 여기에있는 경우 Rand ()의 출력도 예측할 수 있습니다.
실제로 임의의 숫자를 생성하려는 이유와 "무작위"가 당신에게 허용 가능한 임의의 방법에 달려 있습니다. 당신의 예에서, 그것은 빠른 연속으로 복제를 피할 수 있으며, 그것은 당신에게 충분할 수 있습니다. 결국, 중요한 것은 그것이 실행된다는 것입니다.
거의 모든 플랫폼에서는 rand ()보다 난수를 생성하는 더 좋은 방법이 있습니다.
글쎄, 그것은 완료 할 필요가없는 추가 처리입니다.
이 시나리오에서는 루프를 시작하기 전에 시간 기반 씨앗으로 생성자를 한 번 호출합니다. 이는 모든 반복에 대한 교체를 변경하는 여분의 오버 헤드없이 임의의 결과를 보장합니다.
나는 당신의 방법이 어떤 것이라고 생각하지 않을 것입니다 더 그보다 무작위.
당신은 무작위 숫자 생성을 생각할 수 있습니다 (이것은 더 이상 진실한 구현이 아니라 더 이상 진정한 구현이 아니라 그림으로 작용할 수 있음)을 값 표로 생각할 수 있습니다. 간단한 임의의 샘플을 수행하기 위해 통계 에서이 작업을 수행하는 것을 기억한다면, 씨앗은 기본적으로 큰 임의의 숫자 테이블에서 시작할 행과 열을 알려줍니다. 우리는 이미 숫자가 이미 정상적으로 분포되어 있다고 가정 할 수 있기 때문에 반복해서 다시 재조정하는 것은 불필요합니다.
응용 프로그램에 따라 충분해야하므로 두 번 이상 파종하는 데 추가 이점이 없습니다. "더 많은"랜덤 숫자가 필요하면 많은 무작위 숫자 생성 방법이 있습니다. 내가 생각할 수있는 한 가지 사례는 스레드 안전 방식으로 난수를 생성하는 것입니다.
솔루션은 허용되지만 숫자는 전 세계적으로 한 번 파종하는 것보다 더 무작위가되지 않습니다. Srand는 일반적으로 생성자에 속하지 않아야합니다. 임의의 숫자를 지원하려면 프로그램이 시작될 때 한 번 시드하고 잊어 버리십시오.