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

Как сгенерировать одну и ту же последовательность случайных чисел по нескольким типам компиляторов и ядер с помощью <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
4b9b3361

Ответ 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, если вы хотите полную переносимость.