Подтвердить что ты не робот

Широкий диапазон равномерного распределения

Итак, у меня есть случайный объект:

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);
}

Какой лучший способ я могу изменить (через другую функцию или иначе) верхнюю границу распределения?

(также желающий советоваться с другими проблемами стиля)

4b9b3361

Ответ 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;
}