c ++ srand не дает одинаковые последовательности случайных чисел

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

#define RN rand()/(RAND_MAX+1.0)
int main(int argc, char **argv)
{
    unsigned int seed=47456536;
    srand(seed);
    // a lot of stuff including RN
}

Проблема в том, что в разных прогонах я получаю разную последовательность чисел. Это возможно?


person Cristina    schedule 06.02.2015    source источник
comment
Я установил начальное число на определенное число, чтобы получить одну и ту же последовательность случайных чисел при разных запусках программы. Зависит от фактической реализации генератора случайных чисел, но гарантированные последовательности случайных чисел заводятся с seed(0) AFAIK.   -  person πάντα ῥεῖ    schedule 07.02.2015
comment
см. комментарии к моему ответу. Думаю, ты ошибаешься, @ πάνταῥεῖ.   -  person Marcus Müller    schedule 07.02.2015
comment
Пробовал с 0, не помогло. Я не думаю, что имеет значение, какое семя вы выберете. Пока это один и тот же номер, он должен давать одинаковую последовательность. Насколько мне известно   -  person Cristina    schedule 07.02.2015
comment
@ πάνταῥεῖ почему может существовать такое случайное ограничение. Семя - это семя, это семя ...   -  person sehe    schedule 07.02.2015
comment
Воспроизведите проблему с помощью минимального количества кода. То есть, только вызов srand(), затем несколько вызовов std::cout << rand() << "\n";. Это все еще происходит? Например, ideone.com/U14x0g.   -  person indiv    schedule 07.02.2015
comment
Как говорят другие, либо в используемой вами stdlib что-то сильно не работает, либо что-то не так в вашем коде большого количества вещей. Я предполагаю последнее, но если вы не покажете этот код (или минимальное количество для воспроизведения), нет никакого способа быть уверенным   -  person Jcl    schedule 07.02.2015
comment
rand()/(RAND_MAX+1.0) может привести к разным результатам (особенно если вы используете алгоритм, который объединяет ошибки), я не думаю, что существует какое-либо стандартное требование, чтобы это деление выполнялось с одинаковой точностью или раундами в одном и том же направлении каждый раз.   -  person M.M    schedule 07.02.2015
comment
@indiv: Да, я пробовал. Но тогда нет никаких проблем. Это происходит только после определенного количества обращений к rand () ок. 100. И у меня действительно огромное количество вызовов rand ().   -  person Cristina    schedule 07.02.2015
comment
@ Кристина, которая подводит итог. Если этого не происходит с минимальным кодом, значит, в вашем коде очевидно что-то не так, что вы не показали.   -  person Jcl    schedule 07.02.2015
comment
(вкратце, это Yes, I did try that. But then there is no issue часть, на случай, если это было неясно)   -  person Jcl    schedule 07.02.2015


Ответы (2)


Во-первых: Сделайте not использовать _1 _ . Здесь являются достаточно лучше альтернативы.

Даже версия стандарта C 1 2011 года говорит в сноске 295:

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

Если это вас не убедило, позвольте мне сделать акцент:

Нет никаких гарантий относительно качества созданной случайной последовательности, и известно, что некоторые реализации создают последовательности с удручающе неслучайными младшие биты. Приложения с особыми требованиями должны использовать генератор, который, как известно, достаточен [читай: не этот] для их нужд.

Однако, если вы решите использовать его вопреки всем причинам, C99 7.20.2.2 и C11 7.22.2.2 определяют функцию srand следующим образом:

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

(3) [...] Реализация должна вести себя так, как если бы ни одна библиотечная функция не вызывала функцию srand.

Это означает 2, что либо ваша стандартная библиотека не работает, вы вызываете неопределенное поведение (например, запись в память, в которую не следует писать) или действительно имеете какой-то другой источник недетерминизма. Как вы наверняка знаете, наиболее распространенными источниками недетерминизма являются многопоточность и чтение ввода (клавиатура, время и т. Д.). Обратите внимание, что вызов _3 _ / _ 4_ из нескольких потоков по своей сути небезопасен 3, кроме порядка выполнения.

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

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

Наконец, позвольте мне еще раз сказать, что вам следует не использовать _7 _ если это вообще возможно.

Если остались сомнения относительно того, что вам следует делать сейчас, просто взгляните на следующую полностью совместимую со стандартами реализацию srand и rand:

#define RAND_MAX 32767
static int _rand_state = 1;
void srand(unsigned int seed) { _rand_state = (int)(seed % 32768); }
int rand() { return (++_rand_state) % 32768; }

Сноски:

1. Если вы используете Linux, справочная страница rand(3) соглашается: «в более старых реализациях rand () и в текущих реализациях в различных системах биты более низкого порядка гораздо менее случайны, чем биты более высокого порядка. Не используйте эту функцию в приложениях, предназначенных для переносимости, когда требуется хорошая случайность».

2. В сочетании с C99 7.20.2.1/3 или C11 7.22.2.1/3, что гарантирует, что реализация ведет себя так, как если бы srand и rand никогда не вызывались какой-либо стандартной библиотечной функцией.

3. C11 явно разрешает гонку данных при использовании этих функций (C11 7.22.2.1/3 и C11 7.22.2.2/3), и C99 сделал бы то же самое, если бы знал концепцию потоков и безопасность потоков.

person gha.st    schedule 06.02.2015
comment
вау, это могло быть немного не по теме, но тем не менее красиво написано. Кстати: мы обычно используем boost :: mt19937, который достаточно быстрый и действительно довольно белый - person Marcus Müller; 07.02.2015
comment
@ MarcusMüller На мой взгляд, основная проблема OP заключается в том, что rand использует центральное (даже не поточно-ориентированное) состояние. Гораздо труднее облажаться, не заметив, когда ваше состояние связано с реальным генератором ... Тем не менее, я, возможно, немного разглагольствовал ... - person gha.st; 07.02.2015
comment
ну, иногда разглагольствования - это хорошо; в данном случае это иллюстрирует причину, по которой последовательность OP rand () не статична. - person Marcus Müller; 07.02.2015

Нет, поскольку генератор случайных чисел определен как детерминированный с фиксированным начальным числом.

Возможно ли, что ваше «множество вещей, включая RN» может изменить порядок вещей, возможно, в зависимости от времени?

РЕДАКТИРОВАТЬ: «переупорядочивание»: существуют ли внешние факторы (время, данные из файлов, несколько запланированных потоков и т. Д.), Которые могут повлиять на порядок, в котором запрашиваются случайные числа?

РЕДАКТИРОВАТЬ: вы можете попробовать использовать что-то вроде ГСЧ Boost; У меня был отличный опыт работы с boost::mt19937, и тот факт, что у вас могут быть «объекты» генератора, исключает возможность того, что какая-то библиотека, которую вы используете, также получает случайные числа через rand, испортив вашу последовательность.

person Marcus Müller    schedule 06.02.2015
comment
Нет, поскольку генератор случайных чисел определен как детерминированный при фиксированном начальном значении. Почему нет? Вы прочитали вопрос? OP на самом деле спрашивает, почему предоставление фиксированного начального числа создает разные последовательности случайных чисел. - person πάντα ῥεῖ; 07.02.2015
comment
Не могли бы вы пояснить, что будет означать изменение порядка вещей? Единственный вызов в коде для srand - это тот. В какой-то момент во время выполнения i-й вызов RN дает разные результаты для run1 и run2. Спасибо - person Cristina; 07.02.2015
comment
@ πάνταῥεῖ: боюсь, ты ошибаешься. Две разные инициализации с одним и тем же семенем будут генерировать одинаковую последовательность результатов при последующих вызовах rand. согласно cplusplus.com/reference/cstdlib/srand. man srand дает Функция srand () устанавливает свой аргумент в качестве начального числа для новой последовательности псевдослучайных целых чисел, возвращаемых функцией rand (). Эти последовательности можно повторить, вызывая srand () с тем же начальным значением. - person Marcus Müller; 07.02.2015
comment
В документации к функции srand четко сказано, что то, что видит Кристина, никогда не должно происходить. Либо есть очень серьезная ошибка в таком важном методе реализации библиотеки C, которую использует Кристина, либо Кристина ошибается. Что из двух более вероятно? - person Mike Nakis; 07.02.2015
comment
@ MarcusMüller Кто бы ни проголосовал против меня: почему ?? Я не собираюсь раскрывать свои отрицательные голоса :-P ... - person πάντα ῥεῖ; 07.02.2015
comment
@ πάνταῥεῖ: Я думаю, вы поправились, так почему же мой ответ был понижен? - person Marcus Müller; 07.02.2015
comment
Сам очень сомневаюсь, что в библиотеке есть ошибка. Скорее всего, я ошибаюсь или есть фактор скачка данных, который я не заметил. Нет программной и аппаратной потоковой передачи, нет данных из файлов. Больше всего меня удивляет то, что последовательность остается неизменной до определенного момента, а затем становится другой. Вот почему я хотел получить другие мнения по этому поводу. - person Cristina; 07.02.2015
comment
Попробуйте зарегистрировать количество вызовов rand с разными начальными числами. Если вы получаете разное количество запросов на разные семена, вероятно, это ваша проблема. Мы использовали rand с определенным семенем для многих вещей и отследили множество ошибок, потому что иногда его вызывали условно, что сбрасывает всю последовательность. - person Retired Ninja; 07.02.2015
comment
@Cristina, вам действительно стоит отредактировать свой вопрос, чтобы добавить минимальный код, который можно воспроизвести, если вы хотите знать, что не так. С предоставленным вами кодом это вообще невозможно воспроизвести, поэтому мы никак не можем помочь. - person Jcl; 07.02.2015