이 글에서는 C/C++에서 정규 분포(Normal Distribution)를 따르는 난수를 생성하는 방법을 알아보겠습니다. 정규 난수를 얻기 위한 기본 공식은 다음과 같습니다.
𝑧 = √(−2 ln 𝑥1) · cos(2𝜋𝑥2)
여기서 x1과 x2는 0과 1 사이에서 무작위로 선택된 값입니다. 이 방식은 통계학에서 널리 사용되는 박스-뮬러 변환(Box-Muller Transform)의 한 형태로, 균등 분포를 따르는 두 개의 독립적인 난수를 이용해 정규 분포를 따르는 난수를 만들어냅니다.
예제 코드
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
using namespace std;
double rand_gen() {
// 균등 분포를 따르는 난수 값을 반환
return ( (double)(rand()) + 1. )/( (double)(RAND_MAX) + 1. );
}
double normalRandom() {
// 정규 분포를 따르는 난수 값을 반환
double v1=rand_gen();
double v2=rand_gen();
return cos(2*3.14*v2)*sqrt(-2.*log(v1));
}
main() {
double sigma = 82.0;
double Mi = 40.0;
for(int i=0;i<20;i++) {
double x = normalRandom()*sigma+Mi;
cout << " x = " << x << endl;
}
}코드 설명
rand_gen() 함수는 rand()가 반환하는 정수형 난수를 0과 1 사이의 실수 값으로 변환하여 균등 분포(uniform distribution)를 따르는 난수를 생성합니다. 분모와 분자에 각각 1을 더해 주는 이유는 로그 함수의 입력값이 0이 되는 것을 방지하기 위함입니다.
normalRandom() 함수는 앞서 소개한 박스-뮬러 변환 공식을 그대로 구현한 것으로, 표준 정규 분포(평균 0, 표준편차 1)를 따르는 난수를 반환합니다.
main() 함수에서는 원하는 평균(Mi = 40)과 표준편차(sigma = 82)를 곱하고 더하는 방식으로, 실제 목표 분포를 따르는 난수 20개를 생성하여 출력합니다.
실행 결과
x = 1.91628 x = 57.0448 x = 51.4348 x = 53.5612 x = -83.8511 x = -28.9197 x = -76.0576 x = 62.1435 x = 23.9 x = -87.0663 x = 50.6942 x = 94.1685 x = -88.1597 x = 168.502 x = 40.7563 x = 90.1091 x = 16.9218 x = -36.9178 x = 135.969 x = 56.8888
출력 결과를 보면 대부분의 값이 평균인 40 근처에 분포하고 있으며, 평균에서 멀어질수록 해당 값이 나타날 확률이 낮아지는 것을 확인할 수 있습니다. 이는 정규 분포의 특징인 종 모양(bell curve) 분포와 일치하는 결과입니다.