Где инициализировать случайное семя для использования через несколько случайных модулей?


Итак, каждый раз, когда я разрабатываю что-то большое, с несколькими модулями, собирающимися вместе, чтобы построить конечную функциональность, я задаюсь одним и тем же вопросом: где инициализировать случайное семя, если более чем 1 модуль должен использовать случайную функцию?

Если у меня есть определенный класс, который нуждается в random (например, класс, который инициализирует себя сортировкой входного массива с помощью самореализующегося quicksort, поэтому мне понадобится random для выбора pivot), у меня обычно есть частная переменная static bool isRandOn;, так что прежде чем я начну случайный выбор разворота, я проверяю эту переменную и делаю srand(time(NULL));, если случайный еще не включен.

Если у меня есть тонна служебных функций в пространстве имен, я делаю очень похожую вещь: я помещаю такую переменную в анонимное пространство имен внутри моей библиотеки utils и делаю более или менее то же самое, что и с классом.

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

Итак, Как лучше всего обрабатывать несколько модулей, нуждающихся в случайном затравке? Установить семя в каждом модуле? Не устанавливайте семя вообще, а вместо этого документируйте использование random и заставьте пользователя инициализировать семя, если он хочет использовать модуль? Что-то третье?

4 4

4 ответа:

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

Повышение.Случайность имеет два понятия:

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

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

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

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

Пенелопа дала правильный ответ. Существует некоторый сложный алгоритм для генерации псевдослучайной последовательности чисел позади rand(). Это похоже на некоторую функцию rand_func(prev_rand), которая генерирует следующее псевдослучайное число из предыдущего. Впервые вы называете srand(time(NULL)), который устанавливает prev_rand в этих терминах, предполагая, что time(NULL) является совершенно неопределенным. Таким образом, вы можете безопасно вызывать srand() (который устанавливает ) несколько раз.

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

Лучший способ избежать повторения всегда одной и той же начальной случайной последовательности-это сделать следующее В каждом модуле, где вы вызываете функцию random():

/* Global variable to remember if we already initialized the PRNG */
static bool seed_initialized = false;

/* Helper function to avoid having always the same sequence again and again */
static void
prng_init (unsigned int seed)
{
  if (!seed_initialized)
    {
      srandom (seed);
      seed_initialized = true;
    }
}

И каждый раз, когда вы используете random() в функции, вы начинаете функцию с чего-то вроде:

 /* Initializing PRNG with a 'reasonably strong' random seed for our purpose */
 prng_init (time (NULL) - getpid());

Таким образом, вы гарантируете, что:

  1. Вы инициализируете свой PRNG по крайней мере в первый раз, когда вы проходите;

  2. Вы никогда не будете повторно инициализировать случайную последовательность более одного раза внутри модуля.

Надеюсь на эту помощь!