2016-09-29 3 views
1

Я следил за этим video tutorial (C++/Game Tutorial 8: Random Number Generator). Я написал программу, но каждый раз получаю такой же результат.вопрос с генератором случайных чисел

#include <iostream> 
#include <random> 
#include <string> 
#include <ctime> 

using namespace std; 

int main() 
{ 

    default_random_engine randomGen(time(0)); 
    uniform_int_distribution<int> diceRoll(1, 6); 

    cout << diceRoll(randomGen) << endl; 
    return 0; 
} 

Я использую Code :: Blocks. Я попробовал его в Visual Studio, и он отлично работает. Означает ли это, что это Code :: Blocks?

+0

'' default_random_engine'' имеет полностью реализованное поведение. Вы можете попробовать заменить его, например, '' mt19937'' или '' mt19937_64'' (см. [Соответствующая статья на cppreference.com] (http://en.cppreference.com/w/cpp/numeric/random)) и посмотрите, устраняет ли это вашу проблему. Если это не так, проверьте вывод '' time (0) '' и посмотрите, отличается ли он от выполнения. Если это не так, это ваш преступник, хотя я не могу представить, как *, что * будет происходить последовательно, если вы не запускаете программу несколько раз в секунду. –

+0

Я исправил 'default_random_engine' с' mt19937', теперь он работает. Так почему «default_random_engine» дает мне тот же ответ. Есть ли способ решить ее? – Athul

ответ

4

TL; DR: default_random_engine не дает никаких гарантий. Если вы хотите числовое случайное число, используйте вместо этого mt19937_64. Если вы хотите создать безопасную релевантность (ключи, IV, соли, пароли, ...), найдите CSPRNG, засеянный с random_device, или используйте random_device. Ниже приведен забавный анализ поведения default_random_engineg++.

default_random_engine является реализацией определенных

Как уже упоминался в комментариях, default_random_engine имеет определенную реализацию поведения, и вы должны, вероятно, не использовать его вообще. Реализация определенных означает, что реализация, например, свободно использовать (в) известный XKCD rng:

class default_random_engine 
{ 
public: 
    using result_type = uint32_t; 

    result_type min() const 
    { 
     return 1; 
    } 

    result_type max() const 
    { 
     return 6; 
    } 

    default_random_engine(int) {}; // we don’t care about the argument 

    result_type operator()() const 
    { 
     return 4; // chosen by fair dice roll 
        // guaranteed to be random 
    } 
}; 

default_random_engine не очень хорошо работает с семенами, близких друг к другу

Однако, на самом деле оказывается, просто, что default_random_engine (используется в GNU libstdC++) сильно предвзято относится к семенам, которые в настоящее время выпускаются time(0) и/или в разрешении, который он отбирает с помощью uniform_int_distribution<int>(1, 6). Попробуйте создать сразу несколько случайных чисел в одной программе. Вы найдете такие результаты: 6 6 6 4 6 2 2 3, 6 3 2 1 4 6 3 3, .... Короче говоря, у default_random_engine нет гарантий, и может быть очень плохой RNG для любой цели (по-видимому, даже учась о случайном API, потому что он не кажется случайным при создании одиночного diceroll, засеянного временными отметками эпохи UNIX!).

Итак, я запустил номера. С небольшой программой (см. Ниже) я вычислил распределение вероятности для первого числа рулонов кости, сгенерированного с default_random_engine и mt19937_64, равным 6, нанесенным на график в диапазоне семян. Это с g ++ (Debian 6.1.1-11) 6.1.1 20160802 и libstdC++ 6.1.1-11.

Plot of the probability to get a 6 in the first draw over seed

График показывает вероятность того, чтобы получить 6 с std::uniform_int_distribution<int> (1,6)в первом нарисовать после инициализации соответствующего случайного двигателя с семенами на осях X. Кроме того, текущее время unix отображается как вертикальная черная линия (видно только в верхнем диапазоне диаграммы). Как вы можете видеть, в настоящее время мы находимся в диапазоне, где целочисленное распределение составляет очень, вероятно (100%) для вывода 6 в качестве первого номера с использованием default_random_engine. В отличие от mt19937_64, очень близка ожидаемая вероятность.. Размер бункера для гистограммы составляет 10000 (или примерно 2,8 часа в секундах с момента-unix-эпохи).

Кроме того, в течение всего испытательного диапазона (0 ..4e9-1), default_random_engine фактически производит 6 как первое число с вероятностью приблизительно ⅙. Это просто очень плохо при работе с семенами, которые «близки» (± 1000) друг к другу.

Заключение

Таким образом, в некотором смысле, time(0)является преступник, потому что она медленно меняется. А также, (стандартная библиотека, используемая) Code :: Blocks является виновником, потому что их default_random_engine сосет. Правильный RNG не должен смещаться к определенному результату по столь большому количеству семян. Просто используйте надлежащий RNG и не пытайтесь заставить вещи работать хорошо с default_random_engine, что не гарантируется быть переносимым между компиляторами и стандартными библиотеками.

Используйте один из двигателей с числовым звуком случайных чисел, предоставляемых стандартом C++ 11 (например, упомянутый mt19937_64), если вам нужны случайные числа для численных целей (например, имитация физики игры).

Если вам нужны случайные числа для безопасности ничего соответствующего (генерировать пароли, соли, капельницы для криптографии, ключи, ...), делать не использовать mt19937_64, но использовать CSPRNG высевают с помощью std::random_devicestd::random_device или непосредственно.

Другое примечание, поскольку учебное пособие предназначено для разработки игры: как только сеть начнет играть, вам действительно понадобится независимое от платформы поведение. В таких случаях выбор конкретного двигателя RNG с определенными параметрами имеет жизненно важное значение для достижения воспроизводимых результатов между клиентами и между клиентом и сервером.

Источник

#include <array> 
#include <cstdint> 
#include <iostream> 
#include <random> 
#include <ctime> 

void search() 
{ 
    static constexpr uint32_t SEARCH_MAX = 4000000000; 
    static constexpr uint32_t SEARCH_BLOCKS = 8; 
    static constexpr uint32_t SEARCH_BIN_SIZE = 10000; 
    static constexpr uint32_t SEARCH_BINS = SEARCH_MAX/SEARCH_BIN_SIZE; 
    static constexpr uint32_t SEARCH_STEP = 1; 
    static constexpr uint32_t OUTPUT_STEP = 1000000; 
    std::vector<uint32_t> histogram(SEARCH_BINS); 
    for (uint32_t &member: histogram) member = 0; 


    std::uniform_int_distribution<int> diceRoll(1, 6); 
    static constexpr uint32_t START = BLOCK * (SEARCH_MAX/SEARCH_BLOCKS); 
    static constexpr uint32_t END = START + SEARCH_MAX/SEARCH_BLOCKS; 
    for (uint32_t i = START; i < END; i+=SEARCH_STEP) { 
     rng_engine_to_use foo(i); 
     int roll = diceRoll(foo); 
     if (roll == 6) { 
      histogram[i/SEARCH_BIN_SIZE] += 1; 
     } 
     if (i % OUTPUT_STEP == 0) { 
      std::cerr << ((float)i/SEARCH_MAX * 100) << "% \r" << std::flush; 
     } 
    } 

    for (uint32_t i = START/SEARCH_BIN_SIZE; i < END/SEARCH_BIN_SIZE; ++i) { 
     std::cout << i*SEARCH_BIN_SIZE << " " << histogram[i] << std::endl; 
    } 
} 

int main() 
{ 
    search(); 
} 

I #define d BLOCK быть в 0..7, чтобы построить одну версию для каждого из моих ядер, потому что mt19937_64 занимает довольно много времени, чтобы произвести все эти числа (я только впоследствии понял, что сюжет не будет читабельным, если будет построен по всему диапазону, но meh.). Я заменил rng_engine_to_use на mt19937_64 и default_random_engine каждый и построил построенную гистограмму (см. Выше).

+0

Последний параграф абсолютно критичен! –

+0

@MartinBonner Я довольно сильно отредактировал структуру своего вопроса. С временной шкалы, я полагаю, вы имеете в виду часть о CSPRNG (которую я теперь также на вершине)? –

+0

Я все еще изучаю C++, поэтому я не понял всего в вашем ответе. Другой ответ показал (см. Ниже) использование 'std :: random_device', но он также дает мне тот же результат – Athul

0

Как указано в this post, в теме, где ПО соответствует тому же учебнику Youtube, это может быть time(0), вызывающее эту проблему. Плакат предлагает использовать std::random_device в качестве семени.

#include <iostream> 
#include <string> 
#include <chrono> 
#include <random> 
#include <ctime> 

using namespace std; 

int main() { 
    default_random_engine randomGenerator(std::random_device{}()); 
    // OR: 
    // default_random_engine randomGenerator(
    // (unsigned) chrono::system_clock::now().time_since_epoch().count()); 

    uniform_int_distribution<int> diceRoll(1, 6); 

    cout << "You rolled a " << diceRoll(randomGenerator) << endl; 

    return 0; 
} 
+0

Извините, я получаю тот же ответ здесь. Я пробовал 'mt19937', это работает. Я вывел время (0), он изменился. – Athul

Смежные вопросы