Некоррелированные параллельные случайные семена с C ++ 2011?

В настоящее время у меня есть основное приложение на Фортране, которому нужно начальное число для генерации псевдослучайных чисел.
Я хотел бы запустить много (много) раз это приложение с полностью некоррелированными семенами (и, кроме того, полностью независимыми цепочками псевдослучайных чисел).

Мой вопрос: как создать семена с C ++ 2011?

5

Решение

В вашем основном потоке извлеките одно семя (или последовательность семен) из хорошего случайного источника (например, из /dev/urandom в Linux). Используйте эти данные для заполнения одного корневого PRNG. Тогда используйте тот PRNG для генерации начальных значений для ваших локальных PRNG.

#include <random>
#include <vector>

typedef std::mt19937 rng_type;
std::uniform_int_distribution<rng_type::result_type> udist;

int main()
{
rng_type rng;

// seed rng first, and store the result in a log file:
rng_type::result_type const root_seed = get_seed();
rng.seed(root_seed);

// make thread seeds:
std::vector<rng_type::result_type> seeds(NUMBER_OF_THREADS);
for (auto & n : seeds) { n = udist(rng); }

// make threads...
}

Интерфейс случайного числа в <random> позволяет засевать как из одного целого числа, так и из последовательность целых чисел. Если вам нужна дополнительная случайность, вы можете mt19937 из последовательности нескольких сотен целых чисел.

6

Другие решения

C ++ 11 обеспечивает std::random_device предоставить недетерминированные случайные числа, если источник доступен. Вы должны будете проверить свою реализацию, чтобы убедиться, что это хорошо. libc ++ по умолчанию использует / dev / urandom. libstdc ++ делает то же самое, если макрос _GLIBCXX_USE_RANDOM_TR1 определено. Реализация Visual Studio, к сожалению, не является недетерминированной. редактировать: начиная с VS2012 их реализация использует криптографические сервисы Windows.

Если std::random_device обеспечивает доступ к недетерминированному источнику случайности (обычно / dev / urandom использует криптографический PRNG), тогда этого должно быть достаточно для создания независимых начальных чисел.

#include <random>

int main() {
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 engine(seed);

}

Вместо использования одного значения в качестве начального числа, некоторые механизмы могут работать лучше с большим количеством начальных данных. Начальная последовательность является альтернативой, предусмотренной стандартом. Двигатели могут быть заполнены начальными последовательностями, которые являются объектами, которые вы загружаете с любым количеством данных и которые создают начальные данные на основе этого.

std::random_device r;
std::vector<std::mt19937> engines;

int engines = 50;
for (int i = 0; i < engines; ++i) {
std::seed_seq s{r(), r(), r(), r(), r(), r(), r(), r()};
engines.emplace_back(s);
}

Восемь 32-битных значений, 256 бит, достаточно, но если вы действительно хотите, вы можете использовать больше. Каждый из стандартных механизмов документирует, сколько данных он использует из начальной последовательности.

Например, каждый двигатель MT19937 будет получать mt19937::state_size (624) 32-битные значения из начальной последовательности. Семена, полученные из последовательности семен, не совпадают с исходными данными, но они основаны на этих данных, поэтому мы можем использовать столько случайных данных в последовательности.

std::random_device r;
std::vector<std::uint_least32_t> data;
std::generate_n(back_inserter(data), 624, std::ref(r));

std::seed_seq seed(begin(data), end(data));

std::mt19937 engine(seed); // 'fully' seeded mt19937
6

Вы не можете когда-либо действительно генерировать случайные семена. Вы тянете их откуда-то. Скорее всего, в ОС есть способ получения псевдослучайных значений (/dev/urandom в Linux, например), который можно использовать для заполнения.

Получение метки времени, представляющей текущее время, также является распространенным вариантом — затем, чтобы убедиться, что вы получаете разные начальные значения для каждого потока, просто убедитесь, что они запрашивают метку времени в несколько разное время, и используйте таймер высокого разрешения, чтобы убедиться, что они действительно получают разные значения как семена.

В C ++ 11 нет функции «получить хороший начальный уровень», потому что такая функция по сути бессмысленна. Компьютер не может генерировать случайные данные. Вы должны выбрать что-то, что выглядит достаточно случайным для ваших целей, и использовать это для создания генератора случайных чисел.

0
По вопросам рекламы [email protected]