Skip to content

C & CPP 난수 생성

FoRA edited this page Jan 3, 2021 · 1 revision

C에서와 C++에서의 난수 생성은 다르다(물론 C++에서 C에서의 방법도 되긴 된다).

C 스타일 난수 생성

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

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

  for (int i = 0; i < 5; i++) {
    printf("난수 : %d \n", rand() % 100);
  }
  return 0;
}

위 코드는 난수를 생성하는 것이 아닌 난수 처럼 보이는 의사 난수(pseudo random number)을 생성하는 코드다. 첫 번째 수만 무작위로 정하고, 나머지 수들은 그 수를 기반으로 여러가지 수학적 방법을 통해 난수 처럼 보이는 수열을 만드는 것이다.

  • 무작위로 정해진 첫 번째 수를 시드(seed)라고 한다. C의 경우 srand를 통해 seed를 설정할 수 있다. time(Null)을 통해 프로그램을 실행했던 초를 시드값으로 지정하면 무작위로 숫자가 하나 정해지고 rand()는 호출 할 때마다 시드값을 기반으로 무작위처럼 보이는 수열을 생성한다.

하지만 다음의 문제점이 있다.

  • 같은 시간대에 시작된 프로그램의 경우 모두 같은 의사 난수 수열을 생성한다.
  • 0 부터 99 까지 균등하게 난수를 생성하지 않는다.
  • rand() 자체도 별로 뛰어나지 않다.
    • randn() 함수는 선형 합동 생성기(Linear congruential generator) 이라는 알고리즘을 바탕으로 구현되어 있는데 이 알고리즘은 좋은 품질의 난수열을 생성 못한다.
  • 자세한 것은 Reference 참고

결론

C++ 에서는 C 의 srand 와 rand 는 갖다 버리자!

C++ 스타일 난수 생성

#include <iostream>
#include <random>

using namespace std;

int main() {
  // 시드값을 얻기 위한 random_device 생성.
  random_device rd;

  // random_device 를 통해 난수 생성 엔진을 초기화 한다.
  mt19937 gen(rd());

  // 0 부터 99 까지 균등하게 나타나는 난수열을 생성하기 위해 균등 분포 정의.
  uniform_int_distribution<int> dis(0, 99);

  for (int i = 0; i < 5; i++) {
    cout << "난수 : " << dis(gen) << endl;
  }
}
  • C++ 에서는 좀더 양질의 시드값을 얻기 위해 random_device 라는 것을 제공한다.
  • 만들어진 random_device 객체인 rdmt19937 gen()의 시드값으로 준다.
    • 만약 시드 값을 1234로 지정하고 싶다면 mt19937 gen(1234)로 하면 된다.
    • mt19937은 메르센 트위스터라는 알고리즘을 사용한다.
    • 이 알고리즘은 좋지만 mt19937 객체가 크기가 커서(2KB 이상) 메모리가 부족하다면 minstd_rand도 괜찮다.
  • C++ 의 경우 어디에서 수들을 뽑아낼지 알려주는 분포(distribution) 을 정의해야 한다.
    • 만약 0 ~ 100까지 균등한 확률 분포로 뽑는다면 균등 분포 (Uniform distribution) 객체를 정의해야 한다.
    • uniform_int_distribution<int> dis(0, 100);
  • 이후 dis(gen)을 통해 생성된 난수를 사용할 수 있다.

Reference

씹어먹는 C++ - <17 - 3. 난수 생성()과 시간 관련 라이브러리() 소개>

Clone this wiki locally