Как сгенерировать одну и ту же последовательность случайных чисел по нескольким типам компиляторов и ядер с помощью <random>?
Проблема
Мне нужно создать такую же (псевдо) последовательность случайных чисел на разных машинах и компиляторах. Если я использую одно и то же ядро, кажется, что реализация mersenne twister (MT) в g++ работает хорошо: независимо от того, компилирую ли я свою программу на более новой машине, с g++ 4.9 или 4.7, я получаю одинаковые случайные числа. Но я получаю разные, если я использую более старое ядро или если я перехожу к компилятору Visual Studio. Это нормально, потому что нет гарантии, что mersenne_twister_engine::seed
устанавливает внутреннее состояние для разных компиляторов.
Что я уже пробовал
Я утверждал, что применение operator<<
на генераторе дает уникальный результат, который можно использовать для установки генераторов на других машинах с помощью operator>>
, но в случае mt19937
кажется, что он не работает. Чтобы было ясно, на компьютере A у меня был код
mt19937 generator1A;
uniform_int_distribution<int> distribution(0, 1000);
cout << "Generating random numbers with seed 1000" << endl;
generator1A.seed(1000);
generator1A(); //to advance the state by one so operator>> will give a longer output; this is not necessary indeed
ofstream test("testseed1000.txt");
test << generator1A << endl;
for (int i = 0; i < 10; ++i)
cout << distribution(generator1A) << endl;
И он производит 252, 590, 893,... и длинный файл. Я переношу файл на другой компьютер B и запускаю следующий код:
mt19937 generator1B, generator2B;
uniform_int_distribution<int> distribution(0, 1000);
cout << "Generating random numbers with seed 1000, and with operator>>" << endl;
generator2B.seed(1000);
generator2B(); // to advance the state by one here as well
ifstream test("testseed1000.txt");
test >> generator1B;
cout << "************************" << endl;
cout << generator1B << endl;
cout << "************************" << endl;
cout << "With seed\twith operator>>" << endl;
for (int i = 0; i < 10; ++i)
cout << distribution(generator2B) << "\t" << distribution(generator1B) << endl;
И он производит
654 205
205 115
115 610
Вопрос
Можете ли вы дать советы, как генерировать одинаковые (псевдо) случайные числа, по крайней мере, с VС++ в Windows и g++ на Debian и Ubuntu? Я бы хотел использовать std, если это возможно, и я не хотел бы использовать собственный движок MT.
Примечания:
- создание миллионов случайных чисел, а затем чтение в не является решением
- Мне нужно использовать MSVS для разработки кода и unix-серверов для моделирования.
- кроме двигателей MT также приветствуются, но я предпочитаю MT
Ответы
Ответ 1
Чтобы удалить переменную из этой проблемы, попробуйте просмотреть выходные данные вашего механизма случайных чисел, а не загружать ее в дистрибутив.
Я просто просмотрел несколько страниц документации для uniform_int_distribution
, и он не дает никаких утверждений о том, как используются выходные данные из равномерного генератора случайных чисел. Я не уверен, что говорит стандарт.
Я предсказываю, что вы получаете одинаковые результаты от вашего mersenne twister, но вы загружаете эти выходные данные в две неэквивалентные реализации uniform_int_distribution
.
Если это так, то для получения той же последовательности случайных чисел вам придется использовать внешнюю реализацию функций распределения, чтобы обеспечить получение одинаковых результатов во всех системах.
Ответ 2
Стандарт требует, чтобы двигатели воспроизводили воспроизводимые числа во всех реализациях, указав значение, которое двигатель, построенный по умолчанию, должен произвести при вызове 10000th (он также указывает фактические алгоритмы перехода и генерации для движков). Например, для mt19937
стандарт указывает, что ([rand.predef]/p3):
typedef mersenne_twister_engine<uint_fast32_t,
32,624,397,31,0x9908b0df,11,0xffffffff,7,0x9d2c5680,15,0xefc60000,18,1812433253>
mt19937;
Требуемое поведение: последовательный вызов 10000 th последовательного вызова объекта, построенного по умолчанию типа mt19937
, должен давать значение 4123659995.
Для распределений такого требования нет; вместо этого стандарт говорит, что ([rand.dist.general]/p3):
Алгоритмы для создания каждого из указанных распределений от реализации.
Другими словами, реализации могут использовать разные алгоритмы для распределений, но должны документировать алгоритмы, которые они используют. MSVC и libstdС++ предположительно используют разные алгоритмы.
Вы можете использовать внешнюю реализацию, такую как классы распределения Boost.Random, если вы хотите полную переносимость.