我在很多地方使用C ++随机数实用程序库。它可能不太舒服(例如,没有任意分布的基类),但是 - 我已经学会了忍受它。
现在我碰巧需要从枚举类型中统一采样值。我知道,已经有关于SO的问题了:
然而,那个:假设所有枚举值都是连续的,即它不适用于
enum Color { Red = 1, Green = 2, Blue = 4 }
我们希望以1/3的概率对这三个值中的每一个进行采样。
std::uniform_distribution<>
的功能,即它不适用于您传递它的随机引擎等等。显然我不能使用std::uniform_int_distribution<Color>
,如果只是出于上述原因1。我该怎么做呢?
注意:
答案 0 :(得分:4)
使用Better Enums,可以通过以下方式解决此问题:
template<typename T>
typename T get_uniform_value(std::default_random_engine& eng)
{
std::uniform_int_distribution<int> dist(0, T::_size() - 1);
return T::_values()[dist(eng)];
}
用法示例:
BETTER_ENUM(Channel, int, Red, Green = 2, Blue) // Enum to generate random values of
...
std::default_random_engine rng(std::random_device{}());
Channel r = get_uniform_value<Channel>(rng); // Uniformly distributed between 0, 2 and 3
答案 1 :(得分:2)
这是分布的三种实现,按递增复杂度的顺序排列:
首先,如果我们可以依赖于值不同或者重复值超重,我们就可以将_values()
容器编入索引:
template<class Enum>
struct SimpleEnumDistribution
{
std::uniform_int_distribution<typename Enum::_integral> dist{0, Enum::_size() - 1};
template<class Generator> Enum operator()(Generator& g) { return Enum::_values()[dist(g)]; }
};
否则,我们可以使用拒绝采样,预先计算枚举值范围的最小值和最大值:
template<class Enum>
struct UniformEnumDistribution
{
std::uniform_int_distribution<typename Enum::_integral> dist{
*std::min_element(Enum::_values().begin(), Enum::_values().end()),
*std::max_element(Enum::_values().begin(), Enum::_values().end())};
template<class Generator> Enum operator()(Generator& g)
{
for (;;)
if (auto value = Enum::_from_integral_nothrow(dist(g)))
return *value;
}
};
如果这样效率低(可能枚举值很稀疏),我们可以在初始化时计算查找表:
template<class Enum>
struct FastUniformEnumDistribution
{
std::uniform_int_distribution<std::size_t> dist;
std::array<typename Enum::_integral, Enum::_size()> values;
FastUniformEnumDistribution()
{
std::copy(Enum::_values().begin(), Enum::_values().end(), values.data());
std::sort(values.begin(), values.end());
dist.param(std::uniform_int_distribution<std::size_t>::param_type{0u, static_cast<std::size_t>(
std::distance(values.begin(), std::unique(values.begin(), values.end())) - 1)});
}
template<class Generator> Enum operator()(Generator& g)
{
return Enum::_from_integral_unchecked(values[dist(g)]);
}
};
答案 2 :(得分:0)
在the question you linked to中,假设您希望在枚举器值上进行统一分布。
然而,&#34;在枚举类型上均匀分布&#34;也可能意味着,在枚举的范围上均匀分布,这通常意味着实现选择的基础类型的所有可能值。
还有其他基本问题:
在您展示的情况下
enum Color { Red = 1, Green = 2, Blue = 4 }
据推测,你想要的均匀分布是从0到7(每个枚举器可以使用位掩码进行OR&#39; d。)
假设枚举是:
enum Color { Red = 1, Green = 2, Blue = 3 }
然后大概你只需要分发1,2,3。
我认为您无法期望编译器或任何模板代码能够理解您的意图 - 任何&#34; enum - &gt;均匀分布&#34;代码需要提示,以便它知道哪些枚举器应该与其他枚举器组合,哪些只是选项。
简而言之,我认为你应该完全按照你所关联的问题做什么,并在int
或其他任何内容上生成适当的分布,然后static_cast
将其添加到枚举。并且不要尝试使用一些模板解决方案,试图为每个可能的枚举阅读你的想法。