본문 바로가기
C++

5-2. C++ 난수 만들기

by kwon5346 2024. 2. 5.
반응형

난수 만들기 (Random Number Generation)

  • 실행할 때마다 다른 난수 생성하기

#include <iostream>
#include <cstdlib> // std::rand(), std::srand()
#include <ctime>   // std::time()

using namespace std;

int main()
{
   std::srand(static_cast<unsigned int>(std::time(0)));

   for (int count = 1; count <= 100; ++count)
   {
      cout << std::rand() << "\t";

      if (count % 5 == 0) cout << endl;
   }

   return 0;
}

실행시킬 때마다 다른 난수를 생성하기 위해서 시드넘버에 고정된 숫자를 사용하는 대신
srand에 seed number를 현재 시간과 연결시키는 방법이 있다.
다만 디버깅이 필요하다면 시드 넘버를 고정시키고 반복을 시키면 된다.

  • 특정 정수 사이의 난수 생성하기

#include <iostream>
#include <cstdlib> // std::rand(), std::srand()
#include <ctime>   // std::time()

using namespace std;

int getRandomNumber(int min, int max)
{
   static const double fraction = 1.0 / (RAND_MAX + 1.0);

   return min + static_cast<int>((max - min + 1) * (std::rand() * fraction));
}
int main()
{
   std::srand(static_cast<unsigned int>(std::time(0)));

   for (int count = 1; count <= 100; ++count)
   {
      cout << getRandomNumber(5,8) << "\t";

      if (count % 5 == 0) cout << endl;
   }

   return 0;
}

static으로 선언한 fraction을 static을 빼고 전역 상수로 선언해도 상관없다.

RAND_MAX

RAND_MAX는 난수를 생성할때 나올 수 있는 가장 큰 숫자를 의미한다. 매크로로 정의되어있다.
C언어 스타일로 특정범위의 난수를 생성하는 방법으로는

 cout << rand() % 4 + 5  << "\t";

이 방법도 있다. 숫자범위가 작을때는 상관없지만 큰 범위의 숫자 내에서 난수를 생성할때는
난수가 특정 영역으로 몰리는 문제가 생길 수도 있다.
그래서 정밀함이 필요할 경우에는 random library를 사용하는게 좋다.

  • random 라이브러리 사용

#include <iostream>
#include <cstdlib> // std::rand(), std::srand()
#include <ctime>   // std::time()
#include <random>

using namespace std;

int main()
{
   std::random_device rd;
   std::mt19937 mersenne(rd()); 
   std::uniform_int_distribution<> dice(1,6);

   for (int count = 1; count <= 20; ++count)
      cout << dice(mersenne) << endl;

   return 0;
}

아까는 실행할 때마다 난수가 변하게 만들기 위해 time을 연동시켰지만,
여기서는 별도의 random divece를 제공해주고 있다.

mt19937은 32비트 짜리 난수를 생성해준다.
(mt19937_64는 64비트 난수를 생성해준다.)
mersenne은 mersenne twister 알고리즘을 개발한 수학자 이름이고
여기선 변수명이므로 바꿀 수 있다. 여기선 seed를 random_device를 사용하기 때문에
같은 난수 패턴이 발생되는것을 막는다.

uniform_int_distribution<> dice(1,6)은 1부터 6까지 숫자를 모두 동일한 확률로
나오게 한다.

난수를 만드는 순서와 각 줄의 기능을 정리해 보자.

  1. 랜덤 디바이스 만들기
    std::random_device rd;
  2. 생성기를 만들고 랜덤 디바이스를 넣기
    std::mt19937 mersenne(rd()); 
  3. 생성기가 어떤 분포를 따를지 정해서 사용할 분포를 만들기
    std::uniform_int_distribution<> dice(1,6);
  4. 분포가 생성기를 통해 난수 생성
    dice(mersenne)
반응형