C++의 시드 난수 생성기
- C++에서 난수 생성기의 시드 개념
-
srand()
함수를 사용하여 C++에서 난수 생성기 시드 -
time()
함수를 사용하여 C++에서 난수 생성기 시드 - 피해야 할 랜덤 생성기 실수 시드
- 결론
C++와 같은 프로그래밍 언어는 진정한 난수를 생성하지 않습니다. 오히려 컴퓨터는 수학 함수를 사용하여 의사 난수를 생성합니다.
이 기사에서는 난수를 생성할 때 시드의 개념과 C++에서 난수를 생성하는 데 사용되는 함수에 시드를 제공하는 방법에 대해 설명합니다.
C++에서 난수 생성기의 시드 개념
C++는 결정론적 알고리즘을 사용하여 난수 시퀀스를 생성합니다. 따라서 숫자 시퀀스는 순전히 확률적이기보다는 의사 난수입니다.
이 경우 시드는 알고리즘의 시작점 역할을 합니다. 생성된 첫 번째 숫자가 시드인 것처럼 생각해서는 안 됩니다.
오히려 알고리즘은 시드가 정의한 분포에서 무작위로 숫자를 선택합니다. 알고리즘에 동일한 시드를 제공하면 동일한 의사 난수 시퀀스가 생성됩니다.
그러나 대부분의 경우 각 실행에 대해 서로 다른 의사 난수 시퀀스를 생성해야 할 수도 있습니다. 이 경우 알고리즘이 실행될 때마다 다른 시드를 알고리즘에 제공해야 합니다.
srand()
함수를 사용하여 C++에서 난수 생성기 시드
srand()
함수는 부호 없는 정수를 인수로 받아들입니다. 인수를 사용하여 의사 난수를 생성하는 알고리즘을 시드합니다.
통사론:
void srand(unsigned int seed);
srand()
함수에 대한 인수로 1
을 제공하면 의사 난수 생성기를 초기 값으로 초기화합니다. 생성기는 rand()
함수에 대한 마지막 호출과 동일한 결과를 생성합니다.
입력으로 사용자로부터 가져온 임의의 숫자로 의사 난수 생성기를 시드하는 예를 살펴보겠습니다.
예제 코드:
#include <iostream>
using namespace std;
int main() {
unsigned int seed;
cout << "Enter seed value:\n";
cin >> seed;
srand(seed);
cout << "Successfully seeded the generator\n";
return 0;
}
출력:
mohtashim@mohtashim:~/eclipse-workspace/Java2Blog$ g++ seed_example.cc
mohtashim@mohtashim:~/eclipse-workspace/Java2Blog$ ./a.out
Enter seed value:
12
Successfully seeded the generator
time()
함수를 사용하여 C++에서 난수 생성기 시드
이전 방식의 문제점은 사용자가 동일한 숫자를 두 번 이상 입력할 수 있다는 점입니다. 알고리즘이 실행할 때마다 다른 시드를 제공해야 하는 경우 time()
함수를 사용하여 의사 난수 생성기에 시드를 제공하십시오.
C++의 time()
함수는 1970년 1월 1일 UTC 00:00시 이후 경과된 초 수인 현재 UNIX 타임스탬프를 반환합니다.
통사론:
time_t time(time_t* timer);
함수는 time_t
유형의 포인터로 인수를 사용합니다. 함수에 대한 null이 아닌 참조를 매개변수로 제공하면 time_t
유형의 객체를 현재 타임스탬프를 보유하는 매개변수로 설정합니다.
time_t
유형은 산술 유형의 별칭이며 현재 UNIX 타임스탬프 값을 보유할 수 있습니다. 사실상 부호 없는 정수 값입니다.
예제 코드:
#include <iostream>
using namespace std;
int main() {
srand(time(NULL));
cout << "Successfully seeded the generator\n";
return 0;
}
코드는 time()
함수에 대한 인수로 NULL
을 전달합니다. 코드에 따르면 어떤 이유로든 time_t
유형의 개체가 필요하지 않습니다.
출력:
mohtashim@mohtashim:~/eclipse-workspace/Java2Blog$ g++ seed_example.cc
mohtashim@mohtashim:~/eclipse-workspace/Java2Blog$ ./a.out
Successfully seeded the generator
피해야 할 랜덤 생성기 실수 시드
일반적으로 코드의 루프에서 의사 난수 시퀀스를 생성합니다. 대부분의 사람들이 흔히 범하는 실수는 루프가 실행될 때마다 생성기를 시드하는 것입니다.
같은 번호로 시드할 때마다 생성기가 동일한 번호 시퀀스를 생성하기 때문에 이러한 경우에 반복되는 번호를 얻을 수 있습니다.
이는 time()
함수가 과거의 고정 날짜 이후 경과된 시간(초)을 반환하기 때문에 time()
함수를 사용하여 임의 생성기를 시드하는 경우에도 마찬가지입니다.
반면에 루프는 훨씬 빠르게 실행되므로 time()
함수에 대한 각 호출은 초가 지나갈 때까지 동일한 값을 계속 반환합니다. 이런 식으로 생성기에 동일한 값을 시드하게 됩니다.
예제 코드:
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 10; i++) {
srand(time(NULL));
cout << rand() << " ";
}
cout << endl;
return 0;
}
출력:
mohtashim@mohtashim:~/eclipse-workspace/Java2Blog$ g++ seed_example.cc
mohtashim@mohtashim:~/eclipse-workspace/Java2Blog$ ./a.out
1524491454 1524491454 1524491454 1524491454 1524491454 1524491454 1524491454 1524491454 1524491454 1524491454
코드는 루프 내부에 랜덤 생성기를 시드하고 실행 결과는 같은 수가 10번 나옵니다. 이 함정을 피하려면 루프 전에 항상 난수 생성기를 시드해야 합니다.
코드가 루프 외부에 임의 생성기를 시드하는 예를 살펴보겠습니다.
예제 코드:
#include <iostream>
using namespace std;
int main() {
srand(time(NULL));
for (int i = 1; i <= 10; i++) {
cout << rand() << " ";
}
cout << endl;
return 0;
}
출력:
mohtashim@mohtashim:~/eclipse-workspace/Java2Blog$ g++ seed_example.cc
mohtashim@mohtashim:~/eclipse-workspace/Java2Blog$ ./a.out
213462937 1076978976 1207347426 8310730 1551061902 266528745 944000672 871831053 1678325834 868781842
코드로 인해 다른 숫자 시퀀스가 생성되는지 확인합니다.
결론
알고리즘의 시작점 역할을 하는 의사 난수 생성기에 시드를 제공할 수 있지만 기사에서 논의된 것처럼 함정을 피하도록 주의해야 합니다. 그렇지 않으면 원치 않는 결과가 발생할 수 있습니다.
시드 후 의사 난수 시퀀스를 생성하는 rand()
함수에 대한 자세한 내용은 여기를 참조하세요.