C ++ 11 난수 라이브러리를 사용하여 난수 생성 항상 같은

제목에서 알 수 있듯이 새로운 C ++ 11 <random>라이브러리를 사용하여 난수를 생성하는 방법을 찾으려고합니다 . 이 코드로 시도했습니다.

std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);

내가 가진 코드의 문제점은 컴파일하고 실행할 때마다 항상 같은 숫자를 생성한다는 것입니다. 그래서 내 질문은 무작위 라이브러리의 다른 함수가 진정으로 무작위 인 동안 이것을 달성 할 수있는 것입니다.

내 특정 유스 케이스의 경우 범위 내에서 값을 얻으려고했습니다. [1, 10]



답변

Microsoft의 Stephan T. Lavavej (stl)는 Going Native에서 새로운 C ++ 11 임의 함수를 사용하는 방법과 사용하지 않는 이유에 대해 이야기했습니다 rand(). 여기에는 기본적으로 질문을 해결하는 슬라이드가 포함되어 있습니다. 아래 슬라이드에서 코드를 복사했습니다.

그의 전체 연설은 여기에서 볼 수 있습니다 : http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

#include <random>
#include <iostream>

int main() {
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_real_distribution<double> dist(1.0, 10.0);

    for (int i=0; i<16; ++i)
        std::cout << dist(mt) << "\n";
}

우리는 random_device이라는 이름의 난수 생성기를 시드하기 위해 한 번 사용 mt합니다. random_device()보다 느리지 만 mt19937운영 체제 ( 예 : RdRand 와 같은 다양한 위치에서 소스로 제공)에서 임의의 데이터를 요청하므로 시드 할 필요가 없습니다 .


보면 이 질문 / 답변 , 그 표시 uniform_real_distribution되돌 범위의 수를 [a, b)당신이 원하는, [a, b]. 그렇게하려면 uniform_real_distibution실제로 다음과 같아야합니다.

std::uniform_real_distribution<double> dist(1, std::nextafter(10, DBL_MAX));

답변

내 ‘무작위’라이브러리는 C ++ 11 임의 클래스 주위에 매우 편리한 래퍼를 제공합니다. 간단한 ‘get’방법으로 거의 모든 작업을 수행 할 수 있습니다.

예 :

  1. 범위의 난수

    auto val = Random::get(-10, 10); // Integer
    auto val = Random::get(10.f, -10.f); // Float point
  2. 임의의 부울

    auto val = Random::get<bool>( ) // 50% to generate true
    auto val = Random::get<bool>( 0.7 ) // 70% to generate true
  3. std :: initilizer_list의 임의 값

    auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
  4. 반복자 범위 또는 모든 컨테이너의 임의 반복자

    auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator
    auto it = Random::get( vec ); // return random iterator

그리고 더 많은 것들! github 페이지를 확인하십시오.

https://github.com/effolkronium/random


답변

내가 좋아하는 그것에 C와 40 다른 페이지 ++에 대해, 물건 위의 모든 빨간색 와 감시 “STL”스테판 T. Lavavej에서 비디오를
여전히 내가 알아 내기 위해 전체 일요일을했다, 그래서 확인하는 방법 임의의 숫자 작품 실천에 없었다 그것의 모든 것 그리고 그것이 작동하고 어떻게 사용될 수 있는지.

제 생각에 STL은 “더 이상 srand를 사용하지 않는”것에 대해 옳았으며 비디오 2 에서 잘 설명했습니다 . 또한 다음을 사용하는 것이 좋습니다.

a) void random_device_uniform()-암호화 된 생성의 경우이지만 느리게 (내 예제에서)

b) mt19937암호화되지 않은 시드를 생성하는 더 빠르고 기능


나는 내가 접근 할 수있는 모든 주장 된 c ++ 11 권을 꺼내어 Breymann (2015)과 같은 독일 저자가 여전히 복제본을 사용한다는 것을 알았습니다.

srand( time( 0 ) );
srand( static_cast<unsigned int>(time(nullptr))); or
srand( static_cast<unsigned int>(time(NULL))); or

단지와 <random>대신 <time> and <cstdlib>#includings – 그래서 : 단 한 권의 책에서 배울주의하십시오.

의미-C ++ 11 이후로 사용해서는 안됩니다.

프로그램에는 종종 임의의 숫자 소스가 필요합니다. 새로운 표준 이전에 C와 C ++는 rand라는 간단한 C 라이브러리 함수에 의존했습니다. 이 함수는 0에서 32767 이상의 시스템 종속 최대 값 범위까지 균일하게 분포 된 의사 난수 정수를 생성합니다. rand 함수에는 몇 가지 문제점이 있습니다. 대부분의 경우는 아니지만 대부분의 프로그램은 하나는 rand에 의해 생산되었습니다. 일부 응용 프로그램에는 임의의 부동 소수점 숫자가 필요합니다. 일부 프로그램에는 불균일 분포를 나타내는 숫자가 필요합니다. 프로그래머는 rand에 의해 생성 된 숫자의 범위, 유형 또는 분포를 변환하려고 할 때 비 랜덤 성을 종종 나타냅니다. (Lippmans C ++ primer 5 판 2012 인용)


마지막으로 Bjarne Stroustrups에서 최신 20 권의 책 중 최고의 설명을 발견했습니다. “C ++ 2019 둘러보기”, “C ++ 2016을 사용한 프로그래밍 원칙 및 실습”및 “C ++ 프로그래밍 언어 4 판”에서 그의 내용을 알아야합니다. 2014 “및”Lippmans C ++ primer 5 판 2012 “의 일부 예 :

그리고 난수 생성기는 두 부분으로 구성되어 있기 때문에 정말 간단합니다.
(1) 일련의 난수 또는 의사 난수 값을 생성하는 엔진. (2) 해당 값을 범위의 수학적 분포로 매핑하는 분포.


Bjarne Stroustrups는 Microsoft의 STL 직원의 의견에도 불구하고 다음과 같이 씁니다.

에서 표준 라이브러리는 난수 엔진 및 분포 (§24.7)를 제공합니다. 기본적으로 default_random_engine을 사용하십시오. 이는 광범위한 적용 가능성과 저렴한 비용으로 선택됩니다.

void die_roll()Bjarne Stroustrups 의 예제-좋은 아이디어 생성 엔진 및 배포 using (여기에서 더 자세히) .


여기에 표준 라이브러리가 제공하는 난수 생성기를 실용적으로 사용할 수 있도록 <random> 다른 예제가있는 실행 코드가 최소한으로 줄어 들었습니다.

    #include <random>     //random engine, random distribution
    #include <iostream>   //cout
    #include <functional> //to use bind

    using namespace std;


    void space() //for visibility reasons if you execute the stuff
    {
       cout << "\n" << endl;
       for (int i = 0; i < 20; ++i)
       cout << "###";
       cout << "\n" << endl;
    }

    void uniform_default()
    {
    // uniformly distributed from 0 to 6 inclusive
        uniform_int_distribution<size_t> u (0, 6);
        default_random_engine e;  // generates unsigned random integers

    for (size_t i = 0; i < 10; ++i)
        // u uses e as a source of numbers
        // each call returns a uniformly distributed value in the specified range
        cout << u(e) << " ";
    }

    void random_device_uniform()
    {
         space();
         cout << "random device & uniform_int_distribution" << endl;

         random_device engn;
         uniform_int_distribution<size_t> dist(1, 6);

         for (int i=0; i<10; ++i)
         cout << dist(engn) << ' ';
    }

    void die_roll()
    {
        space();
        cout << "default_random_engine and Uniform_int_distribution" << endl;

    using my_engine = default_random_engine;
    using my_distribution = uniform_int_distribution<size_t>;

        my_engine rd {};
        my_distribution one_to_six {1, 6};

        auto die = bind(one_to_six,rd); // the default engine    for (int i = 0; i<10; ++i)

        for (int i = 0; i <10; ++i)
        cout << die() << ' ';

    }


    void uniform_default_int()
    {
       space();
       cout << "uniform default int" << endl;

       default_random_engine engn;
       uniform_int_distribution<size_t> dist(1, 6);

        for (int i = 0; i<10; ++i)
        cout << dist(engn) << ' ';
    }

    void mersenne_twister_engine_seed()
    {
        space();
        cout << "mersenne twister engine with seed 1234" << endl;

        //mt19937 dist (1234);  //for 32 bit systems
        mt19937_64 dist (1234); //for 64 bit systems

        for (int i = 0; i<10; ++i)
        cout << dist() << ' ';
    }


    void random_seed_mt19937_2()
    {
        space();
        cout << "mersenne twister split up in two with seed 1234" << endl;

        mt19937 dist(1234);
        mt19937 engn(dist);

        for (int i = 0; i < 10; ++i)
        cout << dist() << ' ';

        cout << endl;

        for (int j = 0; j < 10; ++j)
        cout << engn() << ' ';
    }



    int main()
    {
            uniform_default();
            random_device_uniform();
            die_roll();
            random_device_uniform();
            mersenne_twister_engine_seed();
            random_seed_mt19937_2();
        return 0;
    }

나는 그것이 모든 것을 추가하고 내가 말했듯이, 그 예를 들기 위해 많은 독서와 시간이 걸렸다 고 생각합니다-숫자 생성에 대한 더 많은 것들이 있다면 PM을 통해 또는 의견 섹션에서 그것에 대해 들려 드리겠습니다 필요한 경우 추가하거나이 게시물을 수정합니다. 부울


답변

다음은 그 라인을 따라 작성한 것입니다.

#include <random>
#include <chrono>
#include <thread>

using namespace std;

//==============================================================
// RANDOM BACKOFF TIME
//==============================================================
class backoff_time_t {
  public:
    random_device                      rd;
    mt19937                            mt;
    uniform_real_distribution<double>  dist;

    backoff_time_t() : rd{}, mt{rd()}, dist{0.5, 1.5} {}

    double rand() {
      return dist(mt);
    }
};

thread_local backoff_time_t backoff_time;


int main(int argc, char** argv) {
   double x1 = backoff_time.rand();
   double x2 = backoff_time.rand();
   double x3 = backoff_time.rand();
   double x4 = backoff_time.rand();
   return 0;
}

~


답변

여기 의사 난수 생성기에 대해 읽을 수있는 자료가 있습니다.

https://en.wikipedia.org/wiki/Pseudorandom_number_generator

기본적으로 컴퓨터의 난수에는 시드가 필요합니다 (이 숫자는 현재 시스템 시간 일 수 있음).

바꾸다

std::default_random_engine generator;

으로

std::default_random_engine generator(<some seed number>);

답변

두 가지 일반적인 상황이 있습니다. 첫 번째는 난수를 원하고 품질이나 실행 속도에 대해 너무 소중하지 않다는 것입니다. 이 경우 다음 매크로를 사용하십시오.

#define uniform() (rand()/(RAND_MAX + 1.0))

RAND_MAX가 double의 정밀도보다 크지 않은 경우 p에서 0-1-epsilon 범위의 p를 제공하지만 올 때 걱정할 필요는 없습니다.

int x = (int) (uniform () * N);

이제 0에서 N -1 사이의 임의의 정수를 제공합니다.

다른 분포가 필요하면 p를 변환해야합니다. 또는 때로는 uniform ()을 여러 번 호출하는 것이 더 쉽습니다.

반복 가능한 동작을 원하면 상수로 시드하고, 그렇지 않으면 time ()을 호출하여 시드하십시오.

이제 품질이나 런타임 성능이 걱정된다면 uniform ()을 다시 작성하십시오. 그러나 그렇지 않으면 코드를 만지지 마십시오. 항상 0에서 1을 뺀 엡실론으로 uniform ()을 유지하십시오. 이제 C ++ 난수 라이브러리를 감싸서 더 나은 uniform ()을 만들 수 있지만 일종의 중간 수준 옵션입니다. RNG의 특성에 신경이 쓰이는 경우 기본 방법이 어떻게 작동하는지 이해하는 데 약간의 시간을 투자하는 것이 좋습니다. 따라서 코드를 완벽하게 제어 할 수 있으며 동일한 시드를 사용하면 플랫폼 또는 연결하는 C ++ 버전에 관계없이 시퀀스가 ​​항상 동일하게 보장됩니다.