Генерация случайных чисел с помощью случайной библиотеки C++11


как следует из названия, я пытаюсь выяснить способ генерации случайных чисел с помощью нового C++11 <random> библиотека. Я пробовал этот код:

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

проблема с кодом, который у меня есть, заключается в том, что каждый раз, когда я компилирую и запускаю его, он всегда генерирует одни и те же числа. Итак, мой вопрос в том, какие другие функции в случайной библиотеке могут выполнить это, будучи действительно случайными?

для моего конкретного случая использования, я пытался получить значение в пределах диапазон [1, 10]

4 109

4 ответа:

Stephan T. Lavavej (stl) из Microsoft рассказал на 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

вот что я только что написал по этим строкам::

#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;
}

~

у вас есть две типичные ситуации. Во-первых, вы хотите случайные числа и не слишком беспокоитесь о качестве или скорости выполнения. В этом случае используйте следующий макрос

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

это дает вам p в диапазоне от 0 до 1 - Эпсилон (если RAND_MAX не больше, чем точность двойника, но беспокоиться об этом, когда вы приходите к нему).

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

теперь дает случайное целое число от 0 до N -1.

Если вам нужно другие дистрибутивы, вы должны превратить стр. Или иногда проще назвать равномерным() несколько раз.

Если вы хотите повторяемое поведение, семя с константой, в противном случае семя с вызовом time().

теперь, если вас беспокоит качество или производительность во время выполнения, перепишите uniform(). Но в противном случае не трогайте код. Всегда сохраняйте равномерность() от 0 до 1 минус Эпсилон. Теперь вы можете обернуть библиотеку случайных чисел C++, чтобы создать лучшую униформу(), но это своего рода вариант среднего уровня. Если вас беспокоят характеристики ГСЧ, то также стоит потратить немного времени, чтобы понять, как работают основные методы, а затем предоставить один. Таким образом, у вас есть полный контроль над кодом, и вы можете гарантировать, что с одним и тем же семенем последовательность всегда будет точно такой же, независимо от платформы или версии C++, на которую вы ссылаетесь.