Coding/C++

[ C++ ] Chapter 5.9 : 난수 random numbers

ted0505 2022. 2. 9. 15:32

# 난수

  • 컴퓨터는 난수를 생성하지 못한다.
    • 계산에 의해 마치 난수처럼, 상관없는 숫자들을 출력하는 것뿐. 

 

# 난수를 생성하는 원리

#include <iostream>

using namespace std;

unsigned int PRNG()
{
	static unsigned int seed = 5523; // 임의로 선택된 시드 값 "5523".
	seed = 8235729 * seed + 2396403;  // OverFlow를 이용.

	return seed % 32768; // [ 0, 32768 ] 사이의 수를 반환.
}

int main()
{
	for (int count = 1; count < 100; ++count) // 난수 100개 생성.
	{
		cout << PRNG() << "\t";  // 난수 생성.
		if (count % 5 == 0) cout << endl;  // 난수 5개 출력 후, 줄바꿈.
	}
}
  • static unsigned int seed = 5523;
    • seed : 초기에 임의로 직접 선택해주는 숫자.
    • 시드 값을 계산해서 임의의 수를 냄.
  • seed = 8235729 * seed + 2396403;
    • unsigned int 에 담지 못하는 overflow 문제를 만들어낸다.
    • 최대한 시드와 관련없고 예측할 수 없는 숫자를 만들어내기 위해서.
    • static 변수는 메모리를 유지.
      • 때문에, seed 값은 반복할 때마다 매번 다른 값으로 갱신.
  • 이 같은 원리로 seed 값을 유지할 경우 매번 같은 패턴이 나옴.
    • 그래서 seed 넘버를 상수로 하지않고, 매순간 변하는 시간을 int 로 형변환하여 설정하기도 한다.
  • seed 넘버가 고정되어있는 것이 나쁜것만은 아님. 디버깅에 유용.

 

# 라이브러리를 사용하여 난수 생성하기

<cstdlib>

  • std::srand(); : 매개변수에 seed 넘버를 입력.
  • std::rand(); : seed 넘버로 임의의 수 생성. 
  • seed 넘버가 같으면 같은 패턴을 보인다는 한계점.

<ctime>

  • std::time() : 1970년 1월 1일부터 현재까지 경과된 시간을 초 단위로 반환한다.
std::srand(static_cast<unsigned int>(std::time(0))); // 시드 넘버 설정

for (int count = 1; count <=100; ++count)
{
	cout << std::rand() << "\t"; // 난수 생성 및 출력

	if (count % 5 == 0) count << endl; 
}
  • std::srand(static_cast<unsigned int>(std::time(0)));
    • std::srand()의 seed 넘버를 std::time() 값으로 unsigned int 형으로 스태틱 캐스팅하여 설정.
    • 시간은 매번 변하기 때문에, 출력되는 값 또한 매번 다를 것이다.

 

<random> 라이브러리

  • C ++ 11 부터 사용 가능.
  • 난수가 특정 범위로 몰릴 경우를 없앤다.
    • 각 숫자의 분포는 동일함. 고급난수 생성 가능.
#include <iostream>
#include <random>

using namespace std;

int main()
{
	std::random_device rd;	// 시드 넘버 생성. time 처럼 시드 넘버를 계속 바뀌게 함.
	std::mt19937 mersenne(rd());	// 랜덤 넘버 생성 알고리즘. 메르센은 알고리즘 만든 이.
	std::uniform_int_distribution<> dice(1, 6);	// 1 ~ 6 사이의 수를 랜덤하게 만든다. 단, 각 숫자의 분포는 동일.

	for (int count = 1; count <= 20; ++count)
		cout << dice(mersenne) << endl;	// 랜덤 넘버 생성.
}