Создание случайных чисел с использованием случайной библиотеки С++ 11

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

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

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

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

Ответ 1

Стефан Т. Лававей (stl) из Microsoft выступил с докладом в Going Native о том, как использовать новые случайные функции С++ 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 один раз для random_device генератора случайных чисел с именем mt. random_device() медленнее, чем mt19937, но его не нужно mt19937, потому что он запрашивает случайные данные из вашей операционной системы (которая будет получать данные из разных мест, например, RdRand).


Глядя на этот вопрос/ответ, кажется, uniform_real_distribution возвращает число в диапазоне [a, b), где вы хотите [a, b]. Чтобы сделать это, uniform_real_distibution должен выглядеть так:

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

Ответ 2

Моя "случайная" библиотека обеспечивает удобную оболочку вокруг случайных классов С++ 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

Ответ 3

Здесь что-то, что я написал только по этим строкам::

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

~

Ответ 4

Вот некоторый ресурс, который вы можете прочитать о генераторе псевдослучайных чисел.

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

Как правило, случайные числа в компьютере требуют начального числа (это число может быть текущим системным временем).

замещать

std::default_random_engine generator;

От

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

Ответ 5

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

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

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

int x = (int) (равномерное() * N);

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

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

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

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