Как устранить все источники случайности, чтобы программа всегда давала одинаковые ответы?

У меня есть код C ++, который сильно зависит от выборки (с использованием rand ()), но я хочу, чтобы он был воспроизводимым. Итак, вначале я инициализирую srand () случайным семенем и распечатываю это семя. Я хочу, чтобы другие могли снова запустить тот же код, но инициализировать srand () с тем же семенем и получить точно такой же ответ, как и я.

Но при каких обстоятельствах это гарантировано? Я полагаю, это работает, только если двоичные файлы скомпилированы одним и тем же компилятором в одной системе? Какие еще факторы могут привести к тому, что ответ будет отличаться от того, который я получил изначально?


person Frank    schedule 08.08.2010    source источник
comment
Вот почему я люблю чистый код / ​​функциональное программирование.   -  person strager    schedule 08.08.2010
comment
Предположительно, вы не инициализируете srand () случайным семенем? Или вы находитесь в каком-то бесконечно рекурсивном процессе.   -  person    schedule 08.08.2010
comment
@Neil Ха-ха, хороший момент, я использую смесь clock (), time (NULL) и getpid ().   -  person Frank    schedule 08.08.2010
comment
@strager: Чистота не имеет значения. Речь идет о реализации генератора случайных чисел.   -  person kennytm    schedule 08.08.2010
comment
Имейте в виду, что если ваш код является многопоточным, заполнение генератора случайных чисел не устранит весь ваш недетерминизм. Другими проблемами могут быть системы, в которых не хватает памяти, арифметические различия с плавающей запятой, все, что связано с получением текущего времени или имени хоста ...   -  person Borealid    schedule 08.08.2010
comment
@Borealid Пожалуйста, расскажите подробнее. Я не понимаю, какое отношение к проблеме имеет МП.   -  person    schedule 08.08.2010
comment
@ Нил Баттерворт: Если программа многопоточная, порядок чередования потоков (который не является детерминированным) может повлиять на ее вывод. Также верно для межпроцессного взаимодействия, сетевой передачи сообщений, доступа к разделяемой памяти ... Поскольку выполнение одной и той же программы дважды может иметь два разных результата из-за непостоянства планировщика, ваша программа больше не будет детерминированной после того, как вы сделаете ее параллельной.   -  person Borealid    schedule 08.08.2010
comment
@Borealid Выходные данные генератора все еще детерминированы - это просто происходит в разных потоках.   -  person    schedule 08.08.2010
comment
@ Нил Баттерворт: Тема A: x = 1; y = x+1; print y;. Тема B: y = 1; x = y+1; print x;. Эта программа может давать много разных результатов, но состоит только из двух детерминированных потоков. Вероятно, каждый раз при запуске вы будете получать разные результаты.   -  person Borealid    schedule 08.08.2010
comment
@ Нил Баттерворт: Неважно, выдает ли генератор одну и ту же последовательность чисел, если способ их использования отличается.   -  person Borealid    schedule 08.08.2010
comment
@Neil: Я думаю, что его опасения по поводу многопоточных программ важны, и тем более его намек на арифметические различия с плавающей запятой в разных системах. Меня особенно интересовали эти другие факторы, которые могут повлиять на результат другого запуска.   -  person Frank    schedule 09.08.2010


Ответы (4)


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

person Community    schedule 08.08.2010
comment
Понятно. Итак, если я скажу другим включить, скажем, генератор случайных чисел Boost 1.42, который я использовал, и инициализировать с тем же семенем, которое я использовал, то они получат точно такой же результат? Даже на других платформах и с другим компилятором? - person Frank; 08.08.2010
comment
Я бы добавил, что это правильно, только если вы всегда будете брать числа одинаково. Как и другой, упомянутый в комментариях: например, если вы используете один и тот же генератор чисел для нескольких потоков, результат может быть невоспроизводимым. - person n1ckp; 09.08.2010

Вы правы, что последовательности могут быть разными, если они скомпилированы на разных машинах с разными rand реализациями. Лучший способ обойти это - написать собственный ГПСЧ. На странице руководства Linux для srand приводится следующий простой пример (цитата из стандарта POSIX):

POSIX.1-2001 дает следующий пример реализации rand () и srand (), который может быть полезен, когда нужна одна и та же последовательность на двух разных машинах.

 static unsigned long next = 1;

 /* RAND_MAX assumed to be 32767 */
 int myrand(void) {
     next = next * 1103515245 + 12345;
     return((unsigned)(next/65536) % 32768);
 }

 void mysrand(unsigned seed) {
     next = seed;
 }
person Tyler McHenry    schedule 08.08.2010
comment
Написание собственного ГСЧ - последняя возможная альтернатива, которую вам следует рассмотреть. Вероятно, нет другой функции, в которой так легко ошибиться и так сложно проверить правильность. - person ; 08.08.2010

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

person Oliver Charlesworth    schedule 08.08.2010
comment
Да, просто решите еще раз, что тысячи делали раньше. Это подход настоящего программиста на C. :П - person Frank Osterfeld; 09.08.2010

Ознакомьтесь с реализацией rand () и используйте оттуда один из генераторов случайных чисел, который обеспечивает повторяемость независимо от того, на какой платформе вы работаете.

person Will A    schedule 08.08.2010