Подтвердить что ты не робот

Требует ли std:: mt19937 разминки?

Я читал, что многие генераторы псевдослучайных чисел требуют, чтобы многие образцы в заказе были "разогреты". Это тот случай, когда std:: random_device используется для запуска std:: mt19937, или мы можем ожидать, что он будет готов после построения? Код, о котором идет речь:

#include <random>
std::random_device rd;
std::mt19937 gen(rd());
4b9b3361

Ответ 1

Mersenne Twister представляет собой pRNG на основе сдвигового регистра (генератор псевдослучайных чисел) и поэтому подвержен плохим семенам с длинными прогонами 0s или 1s, которые приводят к относительно прогнозируемым результатам до тех пор, пока внутреннее состояние не будет достаточно перемешано.

Однако конструктор, который принимает одно значение, использует сложную функцию для этого начального значения, которая предназначена для минимизации вероятности создания таких "плохих" состояний. Существует второй способ инициализации mt19937, где вы непосредственно устанавливаете внутреннее состояние, через объект, соответствующий концепции SeedSequence. Это второй способ инициализации, когда вам может потребоваться забота о выборе "хорошего" состояния или разминки.


Стандарт включает объект, соответствующий концепции SeedSequence, называемый seed_seq. seed_seq принимает произвольное количество входных значений семени и затем выполняет определенные операции над этими значениями, чтобы создать последовательность различных значений, подходящих для непосредственной установки внутреннего состояния pRNG.

Здесь приведен пример загрузки последовательности семян с достаточным количеством случайных данных для заполнения всего состояния std::mt19937:

std::array<int, 624> seed_data;
std::random_device r;
std::generate_n(seed_data.data(), seed_data.size(), std::ref(r));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));

std::mt19937 eng(seq);

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

Хотя здесь я полностью загружаю seed_seq из std::random_device, seed_seq указан так, что только несколько чисел, которые не особенно случайны, должны работать хорошо. Например:

std::seed_seq seq{1, 2, 3, 4, 5};
std::mt19937 eng(seq);

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

Здесь должен быть ваш "по умолчанию" для посева:

std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 rng(seed);

Ответ 2

Я считаю, что есть ситуации, когда MT можно посеять "плохо", что приводит к неоптимальным последовательностям. Если я правильно помню, то посев со всеми нулями является одним из таких случаев. Я бы порекомендовал вам попробовать использовать генераторы WELL, если это серьезная проблема для вас. Я считаю, что они более гибкие - качество семени не имеет значения. (Возможно, чтобы более точно ответить на ваш вопрос: возможно, более эффективно сосредоточиться на посеве, а не на посеве, а затем попытаться создать кучу образцов, чтобы получить генератор в оптимальное состояние.)