Я делаю игру в C++, и он связал заполняющиеся мозаики со случайными булевскими переменными (или да или не), является ли это да или не решено rand() % 1
. Это не чувствует себя очень случайным.
Я использую srand
с ctime
при запуске, но кажется, что те же шаблоны подходят.
Есть ли какие-либо алгоритмы, которые создадут очень случайные числа? Или любые предложения о том, как я мог улучшиться rand()
?
Истинная случайность часто не кажется случайной. Ожидайте увидеть нечетные прогоны.
Но по крайней мере одна вещь, которую вы можете сделать, чтобы помочь, - это избегать использования только самого младшего бита. Процитируем числовые рецепты на C:
Если вы хотите сгенерировать случайное целое число от 1 до 10, вы всегда должны делать это, используя старшие биты, как в
j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
, и никогда не используя ничего похожего на
j = 1 + (rand() % 10);
(который использует младшие биты).
Кроме того, вы можете рассмотреть возможность использования другого ГСЧ с лучшими свойствами. Алгоритм Xorshift - хорошая альтернатива. Он быстрый и компактный, занимает всего несколько строк на C и должен быть достаточно хорошим статистически практически для любой игры.
Также, если вы повторно засеваете слишком быстро, вы получите точно такой же номер. Лично я использую класс, который обновляет начальное число только при изменении времени.
Для получения хороших результатов со случайными числами вам действительно нужен генератор, который объединяет результаты нескольких генераторов. Отказ от нижнего бита - довольно глупый ответ.
Умножение с переносом прост в реализации и дает хорошие результаты, а если у вас их несколько и объедините результаты, вы получите чрезвычайно хорошие результаты. Он также не требует много памяти и работает очень быстро.
Люди говорят, что младшие биты не случайны. Так что попробуйте что-нибудь из середины. Это даст вам 28-й бит:
(rand() >> 13) % 2
Кнут предлагает генерацию случайных чисел методом вычитания. Это считается довольно случайным. Пример реализации на языке Scheme см. здесь
Младшие биты стандартных генераторов случайных чисел не очень случайны, это хорошо известная проблема.
Я бы посмотрел в библиотеку ускоренных случайных чисел .
Быстрая вещь, которая может сделать ваши числа более случайными, - это повторно заполнить генератор каждый раз, когда условие if (rand ()% 50 == 0)
верно.
Я успешно использовал генератор случайных чисел Mersenne Twister в течение многих лет. Его исходный код доступен на математическом факультете Университета Хиросимы здесь . (Прямая ссылка, так что вам не нужно читать по-японски!)
В этом алгоритме замечательно то, что:
Я бы рекомендовал взглянуть на него для вашей игры.
Многие генераторы псевдослучайных чисел страдают от циклических младших битов, особенно линейных конгруэнтных алгоритмов, которые обычно являются наиболее распространенными реализациями. Некоторые предлагают убрать младшие биты, чтобы решить эту проблему.
Самое простое, что вы можете сделать, кроме написания еще одного ГПСЧ или использования библиотеки, - это просто использовать все битов, которые дает вам один вызов rand ()
. Большинство генераторов случайных чисел можно разбить на поток битов, который имеет определенную случайность и статистические свойства. Отдельные биты, равномерно распределенные в этом потоке, не обязательно должны иметь одинаковые свойства. По сути, здесь вы отбрасываете от 14 до 31 бита псевдослучайности.
Вы можете просто кэшировать число, сгенерированное вызовом rand ()
, и использовать каждый его бит (в зависимости от количество битов rand ()
, конечно же, будет зависеть от RAND_MAX
). Поэтому, если ваш RAND_MAX
равен 32768, вы можете последовательно использовать 15 младших битов этого числа. Особенно, если RAND_MAX
настолько мал, что вы не имеете дело с младшими битами генератора, поэтому взятие битов с высокого уровня не принесет вам много. Например, Microsoft CRT генерирует случайные числа с помощью уравнения
x n + 1 = x n · 214013 + 2531011
, а затем смещается. младшие 16 бит этого результата и ограничивают его 15 битами. Так что никаких младших битов от генератора нет. Это в значительной степени справедливо для генераторов, где RAND_MAX
достигает 2 31 , но иногда на это нельзя рассчитывать (так что, возможно, ограничьтесь 16 или 24 битами, взятыми из
Итак, как правило, просто кешируйте результат вызова rand ()
и последовательно используйте биты этого числа для своего приложения вместо rand ( )% 2
.
Идеальный способ случайного выбора Да или Нет переключает их. Вам может не понадобиться случайная функция.
Биты младшего разряда не очень случайны.
Используя% 2, вы проверяете только нижний бит случайного числа.
Предполагая, что вам не нужна случайность криптостойкости.
Тогда должно быть нормально следующее:
bool tile = rand() > (RAND_MAX / 2);