Почему использование rand () считается плохим? - PullRequest
0 голосов
/ 18 октября 2018

Я слышал, как некоторые парни говорили, что использовать rand() плохо ДАЖЕ ПОСЛЕ ИСПОЛЬЗОВАНИЯ srand(), чтобы получить семя.Почему это так?Я хочу знать, как все это происходит ... И извините за другой вопрос ... но какая альтернатива этому тогда?

Ответы [ 6 ]

0 голосов
/ 18 октября 2018

Что плохо в rand / srand, так это то, что rand -

  • использует неуказанный алгоритм RNG, однако
  • позволяет инициализировать RNG с помощью srand для повторяемой «случайности».

Эти два пункта, взятые вместе, затрудняют способность реализаций улучшать реализацию ГСЧ (например, использовать криптографический или иным образом «лучший» ГСЧ).Например, JavaScript Math.random и FreeBSD arc4random не имеют этой проблемы, так как они не позволяют приложениям заполнять их для повторяемой «случайности» - именно по этой причине движок JavaScript V8 смог изменить егоРеализация Math.random для варианта xorshift128+ с сохранением обратной совместимости.(С другой стороны, позволить приложениям предоставлять дополнительные данные для дополнения случайности, как в BCryptGenRandom, менее проблематично; даже в этом случае, однако, это обычно наблюдается только в криптографических RNG.)

Также:

  • Тот факт, что алгоритм ГСЧ и процедура заполнения не определены, означает, что даже воспроизводимая «случайность» не гарантируется между rand / srand реализациями, между версиямиодной и той же стандартной библиотеки , между операционными системами и т. д.
  • Если srand не вызывается раньше, чем rand, rand ведет себя так же, как если бы srand(1) был вызван первым.На практике это означает, что rand может быть реализован только как PRNG, а не как недетерминированный RNG, и что алгоритм PRNG rand не может отличаться в данной реализации, независимо от того, вызывает ли приложение srand или нет.
0 голосов
/ 18 октября 2018

Ни один из ответов здесь не объясняет истинную причину того, что rand() плохо .

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

rand() полностью определяется реализацией, но исторически он реализован как Linear Congruential Generator (LCG)) , который обычно является быстрым, но общеизвестно плохим классом PRNG.Младшие биты этих генераторов имеют гораздо меньшую статистическую случайность, чем старшие биты, и сгенерированные числа могут создавать видимые решетчатые и / или плоские структуры (лучшим примером этого является знаменитый RANDU PRNG).Некоторые реализации пытаются уменьшить проблему младших битов, сдвигая биты вправо на заранее определенную величину, однако решение такого типа также уменьшает диапазон вывода.

Тем не менее, есть заметные примеры отличных LCG,как мультипликативные линейные конгруэнтные генераторы L'Ecuyer 64 и 128 битов, представленные в таблицах линейных конгруэнтных генераторов различных размеров и хорошей структуры решетки, Pierre L'Ecuyer, 1999 .

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

0 голосов
/ 18 октября 2018

Во-первых, srand() не получает семя, оно устанавливает семя.Заполнение является частью использования любого генератора псевдослучайных чисел (PRNG).При засевании последовательность чисел, которую PRNG производит из этого начального числа, является строго детерминированной, потому что (большинство?) Компьютеров не имеют средств для генерации истинных случайных чисел.Изменение вашего PRNG не остановит повторяемость последовательности от начального числа, и, действительно, это хорошо, потому что возможность генерировать одну и ту же последовательность псевдослучайных чисел часто полезна.

Так что, если всеPRNG делятся этой функцией с rand(), почему rand() считается плохим?Ну, это сводится к псевдо-части псевдослучайного.Мы знаем, что PRNG не может быть действительно случайным, но мы хотим, чтобы он вел себя как можно ближе к генератору истинных случайных чисел, и есть различные тесты , которые можно применить, чтобы проверить, насколько похожа последовательность PRNGк истинной случайной последовательности.Хотя его реализация не определена стандартом, rand() в каждом обычно используемом компиляторе использует очень старый метод генерации, подходящий для очень слабого аппаратного обеспечения, и результаты, которые он дает довольно плохо в этих тестах.С тех пор было создано много лучших генераторов случайных чисел, и лучше выбрать тот, который соответствует вашим потребностям, а не полагаться на некачественный генератор, который может быть предоставлен rand().

, который подходит для ваших целейзависит от того, что вы делаете, например, вам может потребоваться криптографическое качество или многомерная генерация, но для многих случаев, когда вы просто хотите, чтобы вещи были достаточно равномерно случайными, быстрая генерация и деньги не зависели от качестваиз результатов вы, вероятно, хотите генератор xoroshiro128 + .В качестве альтернативы вы могли бы использовать один из методов в заголовке C ++ <random>, но предлагаемые генераторы не являются современными, и теперь гораздо лучше, но они все еще достаточно хороши для большинства целей иочень удобно.

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

0 голосов
/ 18 октября 2018

Эта история состоит из двух частей.

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

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

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

  • Наиболее заметная проблема этого заключается в том, что ему не хватает механизма распространения : rand дает вам число в интервале [0 RAND_MAX].Он одинаков в этом интервале, что означает, что каждое число в этом интервале имеет одинаковую вероятность появления.Но чаще всего вам нужно случайное число в определенном интервале.Допустим, [0, 1017].Обычно (и наивно) используемая формула - rand() % 1018.Но проблема в том, что, если RAND_MAX не является точным кратным 1018, вы не получите равномерное распределение.

  • Другая проблема заключается в качестве реализации rand.Здесь есть другие ответы, детализирующие это лучше, чем я мог, поэтому, пожалуйста, прочитайте их.

В современном C ++ вам определенно следует использовать библиотеку C ++ из <random>, которая поставляется с несколькими случайнымиопределенные движки (для целочисленных типов и типов с плавающей запятой) и различные распределения.

0 голосов
/ 18 октября 2018

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

C ++ 11 имеет хорошие, намного лучшие, PRNG.Используйте его <random> стандартный заголовок .См., В частности, std::uniform_int_distribution здесь , с хорошим примером выше std::mersenne_twister_engine.

PRNG - очень сложный вопрос.Я ничего о них не знаю, но доверяю экспертам.

0 голосов
/ 18 октября 2018

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

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

ПЛОХО ИСПОЛЬЗОВАТЬ RAND () !!!!

...