Я слышал, как некоторые парни говорили, что использование rand()
плохо ДАЖЕ ПОСЛЕ ИСПОЛЬЗОВАНИЯ srand()
чтобы получить семя. Почему это так? Я хочу знать, как все происходит … И извините за еще один вопрос … но какая альтернатива этому тогда?
Эта история состоит из двух частей.
Первый, rand
это генератор псевдослучайных чисел. Это означает, что это зависит от семени. Для данного семени он всегда будет давать одну и ту же последовательность (при условии, что реализация будет одинаковой). Это делает его непригодным для определенных приложений, где безопасность имеет большое значение. Но это не относится к rand
, Это проблема любого псевдослучайного генератора. И, безусловно, существует множество классов задач, в которых приемлем псевдослучайный генератор. Истинный генератор случайных чисел имеет свои проблемы (эффективность, реализация, энтропия), поэтому для задач, не связанных с безопасностью, чаще всего используется генератор псевдослучайных данных.
Итак, вы проанализировали свою проблему и пришли к выводу, что псевдослучайный генератор является решением. И вот мы приходим к реальным проблемам случайной библиотеки C (которая включает в себя rand
а также srand
) кто конкретно для этого и делает устарелый (a.k.a .: причины, по которым вы должны никогда использование rand
и случайная библиотека C).
Одна проблема заключается в том, что он имеет глобальное государство (установить с помощью srand
). Это делает невозможным использование нескольких случайных движков одновременно. Это также значительно усложняет многопоточные задачи.
Наиболее заметная проблема в том, что ему не хватает механизма распространения: rand
дает вам номер в интервале [0 RAND_MAX]
, Он одинаков в этом интервале, что означает, что каждое число в этом интервале имеет одинаковую вероятность появления. Но чаще всего вам нужно случайное число в определенном интервале. Скажем [0, 1017]
, Обычно (и наивно) используемая формула rand() % 1018
, Но проблема в том, что если RAND_MAX
является точным кратным 1018
вы не получите равномерное распределение.
Еще одной проблемой является качество реализации rand
, Здесь есть другие ответы, детализирующие это лучше, чем я мог, поэтому, пожалуйста, прочитайте их.
В современном C ++ вы обязательно должны использовать библиотеку C ++ из <random>
который поставляется с несколькими случайными четко определенными механизмами (для целочисленных типов и типов с плавающей запятой) и различными распределениями.
Ни один из ответов здесь не объясняет истинную причину rand()
плохой.
rand()
это генератор псевдослучайных чисел (PRNG), но это не значит, что это должно быть плохо. На самом деле, есть очень хорошие PRNG, которые статистически трудно или невозможно отличить от истинных случайных чисел.
rand()
полностью определена реализацией, но исторически она реализована как Линейный конгруэнтный генератор (LCG), который обычно является быстрым, но общеизвестно плохим классом PRNG. Младшие биты этих генераторов имеют гораздо меньшую статистическую случайность, чем старшие биты, и сгенерированные числа могут создавать видимые решетчатые и / или плоские структуры (лучший пример этого — известные Randu ПСЧ). Некоторые реализации пытаются уменьшить проблему младших битов, сдвигая биты вправо на заранее определенную величину, однако такое решение также уменьшает диапазон вывода.
Тем не менее, есть замечательные примеры отличных LCG, таких как мультипликативные линейные конгруэнтные генераторы L’Ecuyer 64- и 128-битные, представленные в Таблицы линейных конгруэнтных генераторов разных размеров и хорошей решеточной структуры, Пьер Л’Экуайер, 1999.
Общее правило: не доверяй rand()
, используйте свой собственный генератор псевдослучайных чисел, который соответствует вашим потребностям и требованиям использования.
Что плохого в rand
/srand
в том, что rand
—
srand
за повторяемость «случайности».Эти два момента, взятые вместе, затрудняют способность реализаций улучшать реализацию RNG (например, использовать криптографический или иным образом «лучший» RNG). Например, JavaScript Math.random
и FreeBSD arc4random
У меня нет этой проблемы, поскольку они не позволяют приложениям заполнять их для повторяемой «случайности» — именно по этой причине движок JavaScript V8 смог изменить его Math.random
реализация к варианту xorshift128+
сохраняя обратную совместимость. (С другой стороны, позволяя приложениям предоставлять дополнительные данные дополнение случайность, как в BCryptGenRandom
менее проблематично; однако даже в этом случае это обычно наблюдается только в криптографических RNG.)
Также:
rand
/srand
реализации, между версиями одной и той же стандартной библиотеки, между операционными системами и т. д.srand
не вызывается раньше rand
является, rand
ведет себя так же, как будто srand(1)
были впервые названы. На практике это означает, что rand
может быть реализован только как ГСЧ, а не как недетерминированный ГСЧ, и что rand
алгоритм PRNG не может отличаться в данной реализации, независимо от того, вызывает ли приложение srand
или нет.Во-первых, srand()
не получает семя, оно устанавливает семя. Заполнение является частью использования любого генератора псевдослучайных чисел (PRNG). Последовательность чисел, которую PRNG производит из этого начального числа, является строго детерминированной, потому что (большинство?) Компьютеров не имеют средств для генерации истинных случайных чисел. Изменение вашего PRNG не помешает повторению последовательности из начального числа, и, действительно, это хорошо, потому что возможность генерировать одну и ту же последовательность псевдослучайных чисел часто бывает полезна.
Так что если все PRNG поделятся этой функцией с rand()
почему rand()
считается плохим? Ну, это сводится к псевдо-части псевдослучайного. Мы знаем, что PRNG не может быть действительно случайным, но мы хотим, чтобы он вел себя как можно ближе к истинному генератору случайных чисел, и есть различные тесты это может применяться для проверки того, насколько последовательность PRNG похожа на истинную случайную последовательность. Хотя его реализация не определена стандартом, rand()
в каждом обычно используемом компиляторе используется очень старый метод генерации, подходящий для очень слабого аппаратного обеспечения, и результаты, которые он дает достаточно плохо в этих тестах. С этого времени было создано много лучших генераторов случайных чисел, и лучше выбрать тот, который соответствует вашим потребностям, а не полагаться на некачественный генератор, который может быть предоставлен rand()
,
То, что подходит для ваших целей, зависит от того, что вы делаете, например, вам может потребоваться криптографическое качество или многомерная генерация, но для многих случаев, когда вы просто хотите, чтобы вещи были достаточно равномерно случайными, быстрая генерация и деньги не были потрачены. линия, основанная на качестве результатов, которые вы, вероятно, хотите xoroshiro128 + генератор. В качестве альтернативы вы можете использовать один из методов в C ++ <random>
заголовок, но предлагаемые генераторы не являются современными, и теперь гораздо лучше, но они все еще достаточно хороши для большинства целей и довольно удобны.
Если деньги находятся на линии (например, для перетасовки карт в онлайн-казино и т. Д.) Или вам необходимо криптографическое качество, вам необходимо тщательно исследовать соответствующие генераторы и убедиться, что они точно соответствуют вашим конкретным потребностям.
Если вы используете rand (), вы получите тот же результат после генерации случайного числа.
Таким образом, даже после использования srand () будет легко предсказать сгенерированное число, если кто-то сможет угадать семя, которое вы используете. Это связано с тем, что функция rand () использует специальный алгоритм для получения таких чисел.
Потратив некоторое время, вы можете выяснить, как предсказать числа, сгенерированные функцией, с учетом начального числа. Все, что вам нужно сейчас, это угадать семя. Некоторые люди называют семя текущим временем. Так что, если вы сможете угадать время, в которое вы запустите приложение, я смогу предсказать число
ПЛОХО ИСПОЛЬЗОВАТЬ RAND () !!!!
rand
обычно, но не всегда, по историческим причинам, очень генератор псевдослучайных чисел (ПСЧ). Насколько это плохо, зависит от конкретной реализации.
C ++ 11 имеет хорошие, намного лучшие, PRNG. Используйте его <random>
стандартный заголовок. Смотри особенно std::uniform_int_distribution
Вот который имеет хороший пример выше std::mersenne_twister_engine
.
PRNG — очень сложная тема. Я ничего о них не знаю, но доверяю экспертам.