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; // 랜덤 넘버 생성.
}