로그램을 작성하면 같은 랜덤변수에 일정한 의도를 가지게 해야될 일이 많다. 일반적으로 쓰이는 랜덤 변수에 구간을 작성하거나 (이전 포스트 내용) 또 어떤 수는 어떤 확률로 나오게 하거나 하나의 수가 동일한 횟수 이전에는 중복되게 하지 않거나 하는 등의 행동이 필요한 경우가 많다. 카드를 뽑을때는 생각해보면 한번 나온 카드는 패를 다시 섞기 전까지는 절대 중복되어서 나오면 안된다. 이런 경우는 크게 2가지 방법을 이용해 해결할 수 있다.

 

1. 정해진 배열안에 필요한 숫자를 넣고 셔플하는 방법 (각 원소간 위치를 랜덤으로 바꾸는 방법을 통해 원소들을 섞는 방법)

2. 새로운 숫자를 뽑을 때 마다 이전에 뽑은 숫자와 비교해서 중복여부를 판단하고 다시 랜덤 함수를 통해 새로운 함수를 뽑는방법.

 

1번 방법은 랜덤수를 뽑기 위해서 추가적인 저장공간이 필요하다는 단점이 있으며 2번 방법은 최악의 경우 너무 많은 랜덤함수를 요구한다는 단점이 있다. 그렇기 때문에 프로그램의 성격에 따라서 두가지 방법 중 보다 효율적인 방법을 택하면 된다.

예로 1~10까지의 숫자를 랜덤으로 중복 없이 뽑는 방법을 1번 방법으로 구현해보면 아래와 같다.

#include <iostream>
#include <time.h>
#define MAX_ARRAY	10

using namespace std;

int main(void)  
{  
	srand((unsigned int)time(NULL));

	int _nCardArray[MAX_ARRAY];

	for(int i = 0 ; i < MAX_ARRAY ; i ++)	//배열에 숫자를 넣어준다.
	{
		_nCardArray[i] = i + 1;}

	for(int i = 0 ; i < 1000 ; i ++)		//1000번 셔플한다.
	{
		int _nDest = rand() % MAX_ARRAY;
		int _nSrc  = rand() % MAX_ARRAY;
		swap(_nCardArray[_nDest], _nCardArray[_nSrc]);}

	for(int i = 0 ; i < MAX_ARRAY ; i ++)	//셔플된 배열을 출력해본다.
	{
		cout << _nCardArray[i] << endl;}
} 

 

지막으로 랜덤에 대해서 고려해볼것은 랜덤 함수가 어떤 형태의 분포를 가지고 있느냐이다. C/C++과 다른 프로그래밍 언어 (특히 수학적인 부분에 특화되어 있는)에서는 2가지 이상의 분포를 가진 랜덤함수를 제공하고 있는 경우도 있다. 하지만 C/C++ 표준 함수에서는 균등분포 (Uniform distribution)만 제공한다. 균등 분포란 말그대로 일정구간내의 값들이 나타날 가능성이 동일한 분포이다. 한마리도 랜덤에 대한 정의에 가장 맞는 분포라고 할 수 있다. 하지만 우리는 이런 균등분포 이외에 정규분포 (Normal distribution) 의 랜덤도 필요한 경우도 많은데 정규분포는 가장 낮은 값과 가장 큰 값이 나올 확률이 적고 중심값이 나올 확률이 높은 분포로 많은 현상을 표현해주는 분포라고 할 수 있다.

위에 그림이 바로 정규분포의 그래프(Gauss 그래프)이다. C/C++에서 이러한 정규분포를 얻기 위해서는 별도로 구현해야 한다.

 

#include <iostream>
#include <time.h>
#include <cmath>
#define MAX_ARRAY	10

using namespace std;

double gaussianRandom(void);

int main(void) {
	srand((unsigned int)time(NULL));

	for (int i = 1; i <= 100; i++)
		cout << gaussianRandom() << endl;

	return 0;
}

double gaussianRandom(void) {
	float v1, v2, s = 0;

	do {
		v1 =  2 * ((float) rand() / RAND_MAX) - 1;      // -1.0 ~ 1.0 까지의 값
		v2 =  2 * ((float) rand() / RAND_MAX) - 1;      // -1.0 ~ 1.0 까지의 값
		s = v1 * v1 + v2 * v2;
	} while (s >= 1 || s == 0);

	s = sqrt( (-2 * log(s)) / s );

	return v1 * s;
}