2009-12-16 2 views
5

Я делаю игру на C++, и она включает в себя заполнение плиток случайными булерами (либо да, либо нет), является ли это да или нет, определяется rand() % 1. Он не чувствует себя очень случайным.Лучше случайный алгоритм?

Я использую srand с ctime при запуске, но похоже, что все те же шаблоны приближаются.

Существуют ли какие-либо алгоритмы, которые будут создавать очень случайные числа? Или любые предложения о том, как я мог бы улучшить rand()?

+0

Просто из любопытства, насколько «большой» является вашим массивом? если его мало, вы можете не видеть много случайности. – GrayWizardx

+0

Можете ли вы показать код? Возможно, что-то просто отвратительно с тем, как вы посеяны, и поэтому он, похоже, имеет последовательную структуру. –

+15

«rand()% 2» даст намного лучшие результаты. –

ответ

22

Истинная случайность часто не кажется очень случайной. Ожидайте увидеть нечетные пробежки.

Но по крайней мере одна непосредственная вещь, которую вы можете сделать, чтобы помочь, заключается в том, чтобы не использовать бит самого низкого порядка. Чтобы процитировать Numerical Recipes в C:

Если вы хотите, чтобы сгенерировать случайное число от 1 до 10, вы всегда должны сделать это с помощью битов высокого порядка, как и в
j = 1 + (int) (10.0 * (rand()/(RAND_MAX + 1.0))); 
и никогда ничем напоминает
j = 1 + (rand() % 10); 
(который использует младшие разряды).

Кроме того, вы можете использовать другой RNG с лучшими свойствами. Алгоритм Xorshift - хорошая альтернатива. Это быстро и компактно на нескольких строках C, и должно быть достаточно статистически для почти любой игры.

+11

Избегание младших бит зависит от генератора. Некоторые PRNG генерируют слабые * старшие * биты вместо этого. – Joey

1

Идеальный способ Да или Нет, как случайное не переключая их. Вам может не понадобиться случайная функция.

+2

Это только я ... или это совсем не случайное ... – LorenVS

+0

Это не так, и ОП сказал, что ему нужны случайные значения. –

+0

+1, @ LorenVS- Как случайно, как и все остальное, возможно, в полностью детерминированной вселенной. –

1

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

Я бы заглянул в boost random number library.

3

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

-2

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

+1

Зачем вам когда-либо перегружать? – Claudiu

+0

Вы никогда не должны повторно посеять. –

+0

Это менее случайный случай, если вы не перегрузите. – user230821

0

Быстрая вещь, которая может заставить ваши номера чувствовать себя более случайными, заключается в повторном посеве генератора каждый раз, когда условие if(rand() % 50==0) истинно.

+2

Что ... точно это условие говорит вам о необходимости повторного посева? – Joey

+0

В зависимости от диапазона генерируемых чисел и генератора чисел он будет * (должен) * автоматически повторно забирать генератор 1 из каждых 50 (или любых других) чисел, генерируемых –

+0

Обратите внимание, что «чувствовать себя более случайным» не равным лучшим статистическим свойствам случайности. PRNG - непостоянные вещи, особенно когда они лечатся неправильно или без особого знания того, что делают (и даже тогда они могут взорваться обратно в ваше лицо). – Joey

8

Биты младшего порядка не очень случайны.
Используя% 2, вы проверяете только нижний бит случайного числа.

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

bool tile = rand() > (RAND_MAX/2); 
+0

На самом деле, используя% 1, они даже не используют нижний бит. :) –

+0

Это смешно. Исправлена. –

+4

У вашего решения такая же проблема, как и у оригинала: только один бит возвращаемого значения rand(). OP использует только самый младший бит, ваше решение использует только самый старший бит. Лучшее решение будет использовать все биты. – sbk

0

Люди говорят, что младшие разряды не случайны. Так что попробуйте что-нибудь посредине.Это даст вам 28-й бит:

(rand() >> 13) % 2 
+0

Получайте удовольствие от Microsoft CRT с этим. Хороший, бесконечный поток нулей :-) – Joey

+0

yees было бы лучше использовать 13 в этом случае – Claudiu

0

Кнут предлагает случайное число поколение методом вычитания. Считается, что он довольно рвадом. Для примера реализации на языке Схемы см. here

+1

Как хорошая книга, как TAoCp, это довольно устаревшая и * много * произошла в исследовании PRNG в прошлом 20 лет. На самом деле субтрактивный метод не намного лучше, чем LCG. – Joey

2

Я использовал генератор случайных чисел Мерсин Твистер успешно в течение многих лет. Его исходный код можно получить в отделе математики Hiroshima Uni here. (Прямая ссылка, так что вам не придется читать по-японски!)

Что хорошего алгоритма является то, что:

  1. Его «случайность» очень хорошо
  2. Ее вектор состояния представляет собой вектор unsigned ints и индекс, поэтому очень легко сохранить его состояние, перезагрузить его состояние и возобновить псевдослучайный процесс, с которого он остановился.

Я бы порекомендовал вам взглянуть на вашу игру.

+0

Покажите мне какой-нибудь PRNG, где второе котируемое преимущество * не * держится. На самом деле это стандартная особенность PRNG. – Joey

4

Проще всего это можно сделать, короткие записи другого ПГСЧ или с использованием библиотеки, было бы просто использовать все биты, один вызов rand() дает вам. Большинство генераторов случайных чисел можно разбить на поток бит, который имеет определенную случайность и статистические свойства. Отдельные биты, равномерно распределенные по этому потоку, не обязательно должны иметь одинаковые свойства. По сути, вы выбрасываете между 14 и 31 бит псевдослучайности.

Вы можете просто кэшировать сгенерированный номер вызовом rand() и использовать каждый бит его (в зависимости от количества битов rand() дает вам, конечно, что будет зависеть от RAND_MAX). Поэтому, если ваш RAND_MAX 32768, вы можете использовать младшие 15 бит этого числа в последовательности. Особенно, если RAND_MAX - это то, что вы не имеете дело с младшими битами генератора, поэтому получение бит с высокого уровня не принесет вам многого. Например, Microsoft ЭЛТ генерирует случайные числа с уравнением

хп + 1 =хн & Мидот; 214013 + 2531011

, а затем сдвигает 16 бит этого младшего разряда и ограничивает его до 15 бит. Таким образом, никакие младшие разряды от генератора отсутствуют. Это в основном справедливо для генераторов, где RAND_MAX достигает 2 , но вы не можете рассчитывать на это иногда (так что, возможно, вы можете ограничить себя 16 или 24 битами, взятыми из верхнего разряда).

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

-1

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

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

+1

Вам не нужно комбинировать генераторы для получения хороших результатов, вам просто нужно использовать хороший генератор. Кроме того, объединение генераторов, не зная, что вы делаете, может привести к плохим результатам. –

1

C++ 11 имеет следующий способ реализации Mersenne tittie twister algorothm. От cppreference.com:

#include <random> 
#include <iostream> 

int main() 
{ 
    std::random_device rd; 
    std::mt19937 gen(rd()); 
    std::uniform_int_distribution<> dis(1, 6); 

    for (int n=0; n<10; ++n) 
     std::cout << dis(gen) << ' '; 
    std::cout << '\n'; 
} 

Это производит случайные числа, подходящие для моделирования без недостатков многих других генераторов случайных чисел. Он не подходит для криптографии; но генераторы криптовальных случайных чисел более интенсивно работают в вычислительной среде.

Существует также алгоритм Well equidistributed long-period linear; с множеством примеров реализации.

Смежные вопросы