[The C++ Programming Language에서 발췌]


    난수는 테스트, 게임, 시뮬레이션, 보안 등의 많은 상황에서 유용하다. <random>에서 표준 라이브러리가 제공하는 폭넓은 난수 생성기의 선택 폭은 이러한 응용 영역의 다양성을 대변하는 것이다. 난수 생성기는 두 부분으로 구성된다.

    [1] 난수나 의사 난수 값의 시퀸스를 생성하는 엔진

    [2] 이러한 값들을 일정 범위의 수학적 분포로 매피아는 분포

    분포 예로는 uniform_int_distribution(생성되는 모든 정수가 동일한 확률을 갖는다.), normal_distribution('종형 곡선'), exponential_distribution(지수 성장 곡선)이 있는데, 각각은 어떤 특정한 범위를 나타낸다. 다음의 예를 살펴보자.


    1
    2
    3
    4
    5
    6
    7
    8
    using my_egine = default_random_engine;                // 엔진의 타입
    using my_distirbution = uniform_int_distribution<>// 분포의 타입
     
    my_engine re {};
    my_distribution one_to_six {16};
    auto die = bind(one_to_six, re); // one_to_six(re)와 동일함
     
    int x = die();
    cs
     

    표준 라이브러리 함수 bind()는 두 번째 인자를 인자로 해서 첫 번째 인자를 호출할 것이다. 따라서 die() 호출은 one_to_six(re)를 호출하는 것과 동일하다.

    범용성과 성능에 대한 철저한 집중 덕택에 한 전문가는 표준 라이브러리의 난수 구성 요소를 '모든 난수 라이브러리가 궁극적으로 원하는 목표'라는 의견을 밝힌 바 있다. 하지만 표준 라이브러리의 난수 구성 요소가 '초심자에게 친숙'하다고 보기는 어려울 수 있다. using문은 기존의 방식을 좀 더 명확하게 표현해준다. 그 방법 대신에 단순히 다음과 같이 작성할 수도 있다


    1
    auto die = bind(uniform_int_distribution<>{16}, default_random_engine{});
    cs


    어떤 버전이 좀 더 이해하기 쉬운가는 전적으로 상황과 독자에 따라 다르다.

    초심자에게는 난수 라이브러리에 대해 완벽하게 범용적인 인터페이스는 상당히 난관이 될 수 있다. 많은 경우에는 간단한 균등 난수 발생기로 시자개도 충분하다. 예를 들면 다음과 같다.


    1
    2
    Rand_int rnd {110}; // [1:10]에 대한 난수 발생기를 만든다.
    int x = rnd();          // x에 [1:10]에 속하는 숫자다.
    cs


    그러면 이것들을 어디에서 얻는단 말인가? die() 같은 건 Rand_int 클래스에서 얻어야 한다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Rand_int
    {
    private :
        default_random_engine re;
        uniform_int_distribution<> dist;
     
    public :
        Rand_int(int low, int high)
            : dist {low, high} {}
     
        const int operator()() { return dist(re); }
    }

    cs


    이러한 정의는 여전히 '전문가 수준'이지만, Rand_int()는 C++ 초보자 코스에 첫 번째주에서도 활용할 수 있다. 다음의 예를 살펴보자.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    int main()
    {
        Rand_int rnd {04};          // 균등 난수 발생기를 만든다.
        
        vector<int> histogram(5); // 크기 5의 벡터를 만든다.
        for (int i = 0; i != histogram.size(); i++)
            ++histogram[rnd()];   // 히스토그램을 [0:4] 범위 숫자의 등장 빈도로 채운다.
     
        for (int i = 0; i != histogram.size(); i++// 막대 그래프를 출력한다.
        {
            cout << i << '\t';
            for (int j =0; j != histogram[i]; j++)
                cout << endl;
        }
    }
    cs


    출력은 균등 분포다.

    0 ******************************

    1 ***************************

    2 *********************

    3 ***************************

    4**************************


    [예제 코드]


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #include <iostream>
    #include <functional>
    #include <random>
    using std::cout;
    using std::endl;
    using std::bind;
     
    auto main(void-> int
    {
        // 랜덤 디바이스 생성
        std::random_device randDeivce;    
        // 예측 불가능 난수 엔진 생성 및 랜덤 디바이스 세팅
        std::default_random_engine randEngine{ randDeivce() };
        
        // -3부터 3까지의 랜덤 정수 출력
        std::uniform_int_distribution<int> dist1{ -33 };
        cout << dist1(randEngine) << endl;
     
        // 1.5부터 3.5까지의 랜점 실수 출력
        std::uniform_real_distribution<double> dist2{ 1.53.5 };
        cout << dist2(randEngine) << endl;
     
        // 정규 분포 (평균, 표준 편차)
        std::normal_distribution<double> dist3{ 2.01.0 };
        cout << dist3(randEngine) << endl;
     
        // 베르누이 분포, (확률(0.0 ~ 1.0)), 성공하면 true를 실패하면 false를 반환함. 
        std::bernoulli_distribution dist4{ 0.7 };
        cout << dist4(randEngine) << endl;
     
        // 베르누이 분포, (시도 횟수, 확률(0.0 ~ 1.0)), 성공한 횟수를 반환 
        std::binomial_distribution<int> dist5{ 1000.5 };
        cout << dist5(randEngine) << endl;
     
        // bind함수로 난수 클래스와 엔진을 하나로 묶는다.
        auto bindDist = bind(std::uniform_int_distribution<int> { -11 }, randEngine);
        cout << bindDist() << endl;
    }
    cs


    Posted by Muramasa