Будет ли случайное семя создать более случайное число? - PullRequest
2 голосов
/ 22 июня 2011

У меня три вопроса о ГСЧ.

Во-первых, какие данные доступны для использования в качестве начального числа. Я всегда использовал время, но должны быть другие легко доступные семена.

Какие легкодоступные семена есть в с ++?

Если бы я повторял ГСЧ через случайные интервалы, основываясь на следующем значении, которое выйдет из ГСЧ, и выбрал случайное начальное число из ответов на вопрос 1, это создаст псевдослучайную цепочку, которую было сложнее предсказать и, следовательно, более случайную

Наконец, каков наилучший способ в c ++ получить случайное число в диапазоне? Я использовал оператор модуля, но хочу что-то, что будет равномерно распределено по диапазону, а не будет благоприятствовать максимуму или минимуму, как для решений ИИ.

Ответы [ 4 ]

3 голосов
/ 22 июня 2011
  1. Это зависит от того, для чего вам нужно rand.Для многих целей вполне достаточно time.Для других меньше так.Я обычно читаю четыре байта из /dev/random на Unix-машине, возвращаясь к time, если /dev/random недоступен.Более эффективным решением было бы использование таймера с более высоким разрешением и хэширование таких вещей, как процесс или идентификатор машины.

  2. Повторное заполнение, вероятно, ничего не изменит, если выиспользуя что-то вроде /dev/random, чтобы сделать это.Большинство других доступных значений довольно предсказуемы.

  3. Если RAND_MAX кратно диапазону, модуль работает нормально.Если это не так, единственное решение - отбросить значения: у вас есть всего RAND_MAX + 1 значений, и вам нужно n.И нет никакого возможного сопоставления, которое отобразит все значения RAND_MAX + 1 на n и будет иметь одинаковое количество входов для каждого n.Обычное решение выглядит примерно так:

    int limit = (RAND_MAX + 1) - (RAND_MAX + 1) % n;
    int result = rand();
    while ( result >= limit )
        result = rand();
    return result % n;

(я полагаю, здесь вы ищете результат в диапазоне [0...n). И что RAND_MAX + 1 выиграл 't переполнение.)

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

2 голосов
/ 22 июня 2011

Вам следует взглянуть на boost::random.

Имейте в виду:

  • Зачем вам нужны случайные числа - для безопасности или длястохастический процесс?
  • Что вы подразумеваете под «более случайным»?
  • Если вы пересеиваете согласно алгоритму, и этот алгоритм более предсказуем, чем базовый ГСЧ, вы хуже, чемВы начали с.Если ваши начальные числа являются просто 32-битными значениями, то даже действительно случайный исходный источник может сделать вещи хуже не лучше!
  • Если вам нужно «добавить» дополнительную случайность из случайногоисточник, может быть лучше сделать это с помощью XOR: т.е. поддерживать небольшой блок действительно случайных чисел и циклически XOR их в выходной сигнал вашего ГСЧ - и вместо повторного повторного заполнения, время от времени регенерируя этот блок.Таким образом, вы не выбрасываете ценное внутреннее состояние ГСЧ.В качестве альтернативы, если у вас есть доступ к внутренним компонентам ГСЧ, используйте реальный случайный источник, чтобы иногда переключать некоторые биты с помощью аналогичного механизма.

Я ожидаю, что вы можете просто использовать boost::mt19937, но это действительно зависит отприменение.

1 голос
/ 22 июня 2011

Одно легкодоступное семя для ГСЧ - это любая функция времени. Начальное число не обязательно должно быть случайным, если оно каждый раз меняется при каждом запуске программы, этого достаточно. Попытка сделать псевдослучайное число «более случайным» - это несколько глупая попытка. Если это необходимо, то генератор не стоит его соли.
Кроме того, если вы не будете регулярно сеять с истинным случайным шумом, вы все равно не сделаете вывод «более случайным», и если вы регулярно будете отбирать истинный случайный шум, только семена будут действительно случайными, остальные значения все еще детерминированы и в целом имеют те же статистические свойства, что и любая другая последовательность, сгенерированная этим генератором.

Обычная реализация для получения чисел в диапазоне не степени двух, если перекошенное распределение неприемлемо, выглядит примерно так:

range = high - low;

while((r = rand()) > range) {}

r += low;

Модули и умножение / деление имеют хорошо известные проблемы с перекосом и переполнением.

Хотя, как вы сказали, если это решение AI, я осмелюсь сказать, что никто не заметит, если один результат на 1% более вероятен, чем другой. Поэтому простое использование по модулю, вероятно, достаточно хорошо, имеет детерминированное время и очень просто. Также обратите внимание, что вы всегда можете выбрать диапазон, который хорошо работает по модулю.

0 голосов
/ 22 июня 2011

Время вполне достаточно для большинства приложений, если вам нужны лучшие случайные числа, вам следует обратиться к конкретным библиотекам, которые предоставляют такую ​​функциональность.

Для генерации диапазона следующее не искажает результаты:

int random = rand() * RANGE / RAND_MAX;

...