Как сгенерировать случайное число, используя стандартную библиотеку C ++ 11 - PullRequest
23 голосов
/ 28 августа 2011

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

srand((unsigned int)time(0));
int i = rand();

Существуют ли разумные значения по умолчанию для механизмов случайных чисел, распределений исемена, которые можно использовать из коробки?

Ответы [ 7 ]

30 голосов
/ 28 августа 2011

Вы должны быть в состоянии сделать что-то вроде:

std::default_random_engine e((unsigned int)time(0));
int i = e();

Качество default_random_engine зависит от реализации. Вы также можете использовать std::min_rand0 или std::min_rand.

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

1012 * Е.Г. *

std::random_device rd;
std::default_random_engine e( rd() );
6 голосов
/ 01 февраля 2013

Унификация и упрощение некоторых из уже предоставленных образцов, я подведу итог:

// Good random seed, good engine
auto rnd1 = std::mt19937(std::random_device{}());

// Good random seed, default engine
auto rnd2 = std::default_random_engine(std::random_device{}());

// like rnd1, but force distribution to int32_t range
auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}()));

// like rnd3, but force distribution across negative numbers as well
auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}()));

Затем я провел несколько тестов, чтобы посмотреть, как выглядят настройки по умолчанию:

#include <random>
#include <functional>
#include <limits>
#include <iostream>

template<class Func>
void print_min_mean_max(Func f) {
   typedef decltype(f()) ret_t;
   ret_t min = std::numeric_limits<ret_t>::max(), max = std::numeric_limits<ret_t>::min();
   uint64_t total = 0, count = 10000000;
   for (uint64_t i = 0; i < count; ++i) {
      auto res = f();
      min = std::min(min,res);
      max = std::max(max,res);
      total += res;
   }
   std::cout << "min: " << min << " mean: " << (total/count) << " max: " << max << std::endl;
}

int main() {
   auto rnd1 = std::mt19937(std::random_device{}());
   auto rnd2 = std::default_random_engine(std::random_device{}());

   auto rnd3 = std::bind(std::uniform_int_distribution<int32_t>{}, std::mt19937(std::random_device{}()));
   auto rnd4 = std::bind(std::uniform_int_distribution<int32_t>{std::numeric_limits<int32_t>::min(),std::numeric_limits<int32_t>::max()}, std::mt19937(std::random_device{}()));

   print_min_mean_max(rnd1);
   print_min_mean_max(rnd2);
   print_min_mean_max(rnd3);
   print_min_mean_max(rnd4);
}

Производит вывод:

min: 234 mean: 2147328297 max: 4294966759
min: 349 mean: 1073305503 max: 2147483423
min: 601 mean: 1073779123 max: 2147483022
min: -2147481965 mean: 178496 max: 2147482978

Так что, как мы видим, mt19937 и default_random_engine имеют разные диапазоны по умолчанию, поэтому рекомендуется использоватьiform_int_distribution.

Кроме того, по умолчанию используетсяiform_int_distribution [0, max_int] (неотрицательный), даже если используется целочисленный тип со знаком. Должен явно указывать диапазон, если вы хотите полный диапазон.

Наконец, важно помнить это в такие моменты.

2 голосов
/ 01 февраля 2013

Вот, пожалуйста. Случайные числа в диапазоне:

// For ints
// replace _real_ with _int_, 
// <double> with <int> and use integer constants

#include <random>
#include <iostream>
#include <ctime>
#include <algorithm>
#include <iterator>

int main()
{
    std::default_random_engine rng(std::random_device{}()); 
    std::uniform_real_distribution<double> dist(-100, 100);  //(min, max)

    //get one
    const double random_num = dist(rng);

    //or..
    //print 10 of them, for fun.
    std::generate_n( 
        std::ostream_iterator<double>(std::cout, "\n"), 
        10, 
        [&]{ return dist(rng);} ); 
    return 0;
}
2 голосов
/ 28 августа 2011

Я использую следующий код в моем проекте.'engine' и 'distribution' могут быть одним из предоставляемых библиотекой.

#include <random>
#include <functional>
#include <iostream>
...
std::uniform_int_distribution<unsigned int> unif;
std::random_device rd;
std::mt19937 engine(rd());
std::function<unsigned int()> rnd = std::bind(unif, engine);

std::cout << rnd() << '\n';
2 голосов
/ 28 августа 2011

Если ваш существующий код был уместен перед новым стандартом, то он останется прежним. Новые генераторы случайных чисел были добавлены для приложений, которые требуют более высокого качества псевдослучайности, например, стохастическое моделирование.

0 голосов
/ 28 августа 2011

Вы можете использовать RC4 для генерации случайных байтов.Это, вероятно, имеет свойства, которые вы хотите.Это быстро и довольно просто реализовать.Последовательность повторяется во всех реализациях, когда начальное число известно, и совершенно непредсказуемо, когда начальное число неизвестно.http://en.wikipedia.org/wiki/RC4

0 голосов
/ 28 августа 2011

Генерация случайных чисел - сложная проблема. Нет действительно случайного способа сделать это. Если вы просто генерируете случайность для создания игровой среды, тогда ваш подход должен быть в порядке У rand () есть несколько недостатков.

Если для генерации ключей шифрования вам нужна случайность, значит, вы S.O.L. Лучший способ в этом случае - выйти на операционную систему, которая обычно имеет механизм. В POSIX это random () (или чтение из / dev / random, если вы так настроены). В Windows вы можете использовать CryptoAPI:

https://www.securecoding.cert.org/confluence/display/seccode/MSC30-C.+Do+not+use+the+rand%28%29+function+for+generating+pseudorandom+numbers

...