C를 먼저 공부하고 C++를 공부하는 사람이라면 난수를 생성할 때 stdlib.h(cstdlib)에 있는 rand 함수를 사용했을 것이다.
rand함수를 사용하면 난수가 생성되는것 처럼 보이지만 실제로 여러번 실행해보면 같은 결과가 나온다.
rand함수를 대략적으로 구성하면 다음과 같을 것이다.
int myRand() {
static int seed = 94263523;
seed = (seed + 998244353) % (1000000007);
return seed;
}
여기에서 시드넘버가 일정하기 때문에 언제나 같은 수가 나올 것이고 실행해보면 난수가 생성된것 처럼 보인다.
이를 해결하기 위해 시드넘버를 현재시간 기준으로 설정하곤 한다.
#include<ctime>
int myRand() {
static int seed = time(nullptr);
seed = (seed + 998244353) % (1000000007);
return seed;
}
이제 실행할 때마다 다른 수가 나와서 더 난수에 가까워진 것 같다.
하지만 이러한 로직은 시간에 의존하여 난수를 발생시킨다.
C++에서는 위와 같은 단순한 난수 발생에서 벗어나 보다 정교한 난수 생성기를 제공한다.
사용법은 다음과 같다.
#include<iostream>
#include<random>
int main() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> uid(0, 100);
for (int i = 0; i < 1000; i++)
std::cout << uid(gen) << std::endl;
}
random_device : 하드웨어에 기반한 비결정적 난수 발생기이다.
mt19937 : 메르센소수를 이용하여 난수를 발생시킨다. 여기서 메르센소수는 $2^p-1$ ($p$는 소수)인 소수이다. $19937$도 소수이고 $2^{19937}-1$도 매우 큰 메르센 소수이다.
uniform_int_distribution : 0~100사이 범위의 정수 난수를 균일하게 발생시킨다. (평균적으로 0~100까지 10번씩 나올것이다.)
위 코드를 사용하면 보다 정교한 난수생성이 가능해진다.
정수는 물론 실수, 정규분포, 베르누이분포, 푸아송분포등 다양한 생성기도 제공하니 자신에게 필요한 난수 발생기를 이용하도록 하자.
* reference
https://en.cppreference.com/w/cpp/numeric/random
'프로그래밍 언어 > C++' 카테고리의 다른 글
[C++] 시간 측정 방법 (0) | 2022.07.21 |
---|