Должен ли я сохранить случайный экземпляр объекта распределения или я всегда могу воссоздать его? - PullRequest
13 голосов
/ 08 декабря 2011

У меня есть этот код:

static std::mt19937 rnd;

// ...

static uint32_t rndInt(uint32_t min, uint32_t max) {
    return std::uniform_int_distribution<uint32_t>(min,max)(rnd);
}

Это хорошая практика или я должен хранить uniform_int_distribution?

Ответы [ 3 ]

9 голосов
/ 08 декабря 2011

Я сомневаюсь, что создание и уничтожение объекта распределения является дорогостоящим, хотя я полагаю, что это может сделать немного больше, чем просто сохранение параметров min,max. Он может предварительно рассчитать некоторые полезные значения на основе параметров, например, в очевидной реализации 2**32 % (max-min+1) - это число различных значений из генератора, которые будут отброшены и повторно опробованы.

В принципе, объекту распределения разрешено хранить внутри себя некоторые биты энтропии, которые были извлечены из генератора при предыдущем вызове operator(), но не нужны. Эти биты могут быть использованы для последующего вызова operator(). Так что если min==0 и max==1, то вы можете получить 32 вызова на operator() в распределении за вызов на генераторе. Вот что такое функция reset(), чтобы очистить это состояние.

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

1 голос
/ 08 декабря 2011

Я обычно делаю следующее:

std::uniform_int_distribution<uint32_t> distrib(16, 97);

Тогда вы можете звонить distrib(rnd) несколько раз, не восстанавливая распределение каждый раз.

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

Кстати, я бы посеял rnd, используя time(NULL) или другой метод посева.

0 голосов
/ 08 декабря 2011

Энтропия хранится в std::mt19937, что означает, что вы продолжите случайную последовательность, но, как заметил Стив Джессоп, у нее все еще есть некоторые накладные расходы для создания объекта. Если вы ожидаете, что эта функция будет вызываться часто с одними и теми же аргументами, вы можете кэшировать std::uniform_int_distribution<uint32_t> объекты на карте, которая использует std::pair<uint32_t, uint32_t> в качестве ключа.

...