Широкий диапазон равномерного распределения
Итак, у меня есть случайный объект:
typedef unsigned int uint32;
class Random {
public:
Random() = default;
Random(std::mt19937::result_type seed) : eng(seed) {}
private:
uint32 DrawNumber();
std::mt19937 eng{std::random_device{}()};
std::uniform_int_distribution<uint32> uniform_dist{0, UINT32_MAX};
};
uint32 Random::DrawNumber()
{
return uniform_dist(eng);
}
Какой лучший способ я могу изменить (через другую функцию или иначе) верхнюю границу распределения?
(также желающий советоваться с другими проблемами стиля)
Ответы
Ответ 1
Объекты распределения легкие. Просто создайте новый дистрибутив, когда вам нужно случайное число. Я использую этот подход в игровом движке, и после бенчмаркинга это сопоставимо с использованием старого старого rand()
.
Кроме того, я спросил, как варьировать диапазон распространения в реальном времени GoingNative 2013, а Стивен Т. Лававей, член стандартного комитета, предложил просто создать новые дистрибутивы, так как это не должно быть производительность проблема.
Вот как я напишу ваш код:
using uint32 = unsigned int;
class Random {
public:
Random() = default;
Random(std::mt19937::result_type seed) : eng(seed) {}
uint32 DrawNumber(uint32 min, uint32 max);
private:
std::mt19937 eng{std::random_device{}()};
};
uint32 Random::DrawNumber(uint32 min, uint32 max)
{
return std::uniform_int_distribution<uint32>{min, max}(eng);
}
Ответ 2
Вы можете просто создать std::uniform_int_distribution<uint32>::param_type
и изменить диапазон, используя метод param()
. Вы можете уменьшить шум шаблона с помощью decltype
:
decltype(uniform_dist.param()) new_range (0, upper);
uniform_dist.param(new_range);
Ответ 3
Я делаю DrawNumber
функцию public
для моего примера. Вы можете предоставить перегрузку, которая берет верхнюю границу, а затем передать новый uniform_int_distribution::param_type
в uniform_int_distribution::operator()
param_type
может быть сконструирован с использованием тех же аргументов, что и соответствующее распределение.
Из N3337, §26.5.1.6/9 [rand.req.dist]
Для каждого из конструкторов D
, принимающих аргументы, соответствующие параметрам распределения, P
должен иметь соответствующий конструктор с одинаковыми требованиями и принимать аргументы, идентичные по числу, типу и значениям по умолчанию. Более того, для каждой из функций-членов D
, возвращающих значения, соответствующие параметрам распределения, P
должна иметь соответствующую функцию-член с идентичным именем, типом и семантикой.
где D
- тип объекта функции распределения случайных чисел, а P
- это тип, названный D
связанным param_type
#include <iostream>
#include <random>
typedef unsigned int uint32;
class Random {
public:
Random() = default;
Random(std::mt19937::result_type seed) : eng(seed) {}
uint32 DrawNumber();
uint32 DrawNumber(uint32 ub);
private:
std::mt19937 eng{std::random_device{}()};
std::uniform_int_distribution<uint32> uniform_dist{0, UINT32_MAX};
};
uint32 Random::DrawNumber()
{
return uniform_dist(eng);
}
uint32 Random::DrawNumber(uint32 ub)
{
return uniform_dist(eng, decltype(uniform_dist)::param_type(0, ub));
}
int main()
{
Random r;
std::cout << r.DrawNumber() << std::endl;
std::cout << r.DrawNumber(42) << std::endl;
}