c++ - Variar la gama de uniform_int_distribution
random c++ 11 (3)
Así que tengo un objeto aleatorio:
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);
}
¿Cuál es la mejor manera en que puedo variar (a través de otra función o de otra manera) el límite superior de la distribución?
(También dispuesto a tomar consejos sobre otros temas de estilo)
Estoy haciendo public
función DrawNumber
para mi ejemplo. Puede proporcionar una sobrecarga que tome un límite superior y luego pasar un nuevo uniform_int_distribution::param_type
a uniform_int_distribution::operator()
El param_type
puede construirse usando los mismos argumentos que la distribución correspondiente.
De N3337, §26.5.1.6 / 9 [rand.req.dist]
Para cada uno de los constructores de
D
tomando argumentos correspondientes a los parámetros de la distribución,P
deberá tener un constructor correspondiente sujeto a los mismos requisitos y tomar argumentos idénticos en número, tipo y valores predeterminados. Además, para cada una de las funciones miembro deD
que devuelven valores correspondientes a los parámetros de la distribución,P
tendrá una función miembro correspondiente con el nombre, tipo y semántica idénticos.
donde D
es el tipo de un objeto de función de distribución de números aleatorios y P
es el tipo nombrado por el param_type
asociado de 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;
}
Los objetos de distribución son ligeros. Simplemente construya una nueva distribución cuando necesite un número aleatorio. Utilizo este enfoque en un motor de juego y, después de la evaluación comparativa, es comparable a usar un buen viejo rand()
.
Además, he preguntado cómo variar el rango de distribución en la transmisión en vivo de GoingNative 2013, y Stephen T. Lavavej, miembro del comité estándar, sugirió simplemente crear nuevas distribuciones, ya que no debería ser un problema de rendimiento.
Así es como escribiría tu código:
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);
}
Simplemente puede crear un std::uniform_int_distribution<uint32>::param_type
y modificar el rango usando el método param()
. Puede reducir el ruido de la plantilla con decltype
:
decltype(uniform_dist.param()) new_range (0, upper);
uniform_dist.param(new_range);