Programming

STL의 난수 발생 방법

C에서 random number를 발생시키기 위해서는 다음과 같은 방법을 많이들 사용한다.

#include <stdlib.h>


int main(void)
{
int i;

srand(time(NULL));
rand();

for (i = 0; i < 10; ++i) {
printf("%d ", rand() % 10);
}
printf("\n");

return 0;
}

C++도 이 srand()와 rand()를 이용할 수 있지만, SGI에서 제안한 STL 스펙으로 Random Number Generator라는 function object(functor)가 있다.

f(N)

스펙에 따르면 위과 같은 형태의 signature를 가지는 random number를 발생시키는 함수들이 제공될 것이므로 다음과 같은 형태는 지양한다.

rand() % N

그러나 구체적인 random number generator functor는 (내가 알고 있기로는) 한 가지를 제외하고는 C++ STL에서는 제공되지 않고 있다. 다행히도 boost library에는 다양한 generator functor가 제공되고 있으니 필요에 따라 적절히 선택해서 사용하면 된다.

굳이 C++ STL에서 난수와 관련된 기능을 찾아서 쓰겠다면 두 가지 선택지가 있다. 하나는 subtractive_rng라는 random number generator functor를 사용하는 것이고, 또 하나는 random_sample 또는 random_sample_n을 사용하는 것이다.

subtractive_rng의 사용 예는 다음과 같다. 아주 간단하다.

#include <iostream>
#include <ext/functional>

using namespace std;
using namespace __gnu_cxx;

int main(void)
{
subtractive_rng rng1; // use the default seed
for (int i = 0; i < 10; ++i) {
cout << rng1(10) << " ";
}
cout << endl;

subtractive_rng rng2(5);
for (int i = 0; i < 10; ++i) {
cout << rng2(10) << " ";
}
cout << endl;

return 0;
}

반면에 random_sample과 random_sample_n은 알고리듬(algorithm)이다. 이 두 함수는 원본 컨테이너에서 임의로 표본을 추출하여 새로운 컨테이너에 복사하는 기능을 제공한다. 위에서 언급한 random number generation과는 약간 궤를 달리하는 기능이다.

#include <iostream>
#include <vector>
#include <ext/algorithm>

using namespace std;
using namespace __gnu_cxx;

int main(void)
{
vector a;
for (int i = 0; i < 10; ++i) {
a.push_back(i);
}

vector b;
b.resize(a.size() / 2);
random_sample(a.begin(), a.end(), b.begin(), b.end());
for (uint i = 0; i < b.size(); ++i) {
cout << b[i] << " ";
}
cout << endl;

return 0;
}

0 7 2 9 6

SGI 스펙에는 여러가지 순열이 나타날 수 있다고 하는데, 실제로 테스트를 반복해보면 동일한 값이 나온다. 이러니 random number generator로 사용하기에는 부적합하니 주의할 필요가 있다.

재미있는 것은 이 함수는 uniform distribution을 따르려고 애를 쓰기 때문에, 위의 예제처럼 원본 컨테이너의 크기보다 샘플링 크기가 작으면 임의로 샘플링되지만, 샘플링 크기가 원본의 크기와 동일하면 그냥 원본의 순서 그대로 샘플링된다.

코드를 다음과 같이 수정하면

 b.resize(a.size());

0 1 2 3 4 5 6 7 8 9

이런 결과가 나온다.

그리고 원본의 크기보다 더 많이 샘플링하면 뒷부분은 모두 0으로 채워진다.

댓글 4개

답글 남기기