【发布时间】:2015-07-18 03:52:03
【问题描述】:
在 Stackoverflow 上,有很多关于从先验未知范围生成均匀分布整数的问题。例如
- C++11 Generating random numbers from frequently changing range
- Vary range of uniform_int_distribution
典型的解决方案是这样的:
inline std::mt19937 &engine()
{
thread_local std::mt19937 eng;
return eng;
}
int get_int_from_range(int from, int to)
{
std::uniform_int_distribution<int> dist(from, to);
return dist(engine());
}
鉴于分发应该是一个轻量级对象并且多次重新创建它不存在性能问题,似乎即使是简单的分发也可能非常好并且通常会有some internal state。
所以我想知道是否通过不断重置它来干扰分布的工作方式(即在每次调用 get_int_from_range 时重新创建分布)我得到正确分布的结果。
Pete Becker 和 Steve Jessop 之间有一个long discussion,但没有最终决定。 在另一个问题(Should I keep the random distribution object instance or can I always recreate it?)中,内部状态的“问题”似乎不是很重要。
C++ 标准是否对此主题做出任何保证?
以下实现(来自N4316 - std::rand replacement)是否更可靠一些?
int get_int_from_range(int from, int to)
{
using distribution_type = std::uniform_int_distribution<int>;
using param_type = typename distribution_type::param_type;
thread_local std::uniform_int_distribution<int> dist;
return dist(engine(), param_type(from, to));
}
编辑
这重用了分发的可能内部状态,但它很复杂,我不确定它是否值得麻烦:
int get_int_from_range(int from, int to)
{
using range_t = std::pair<int, int>;
using map_t = std::map<range_t, std::uniform_int_distribution<int>>;
thread_local map_t range_map;
auto i = range_map.find(range_t(from, to));
if (i == std::end(range_map))
i = range_map.emplace(
std::make_pair(from, to),
std::uniform_int_distribution<int>{from, to}).first;
return i->second(engine());
}
【问题讨论】:
-
从那个链接你从哪里得到“即使是一个简单的分布 [...] 通常也会有一些内部状态”?
-
出于实际目的,为什么要冒险?只使用一个生成器(而不是每个函数调用一个新的)已经很清楚了,那么只使用一个分布有什么问题呢?也许其他解决方案也能完美运行,但您已经有一个可以保证工作的解决方案。
-
@Yakk the incipit of Joseph Mansfield's answer: "一个发行版可能非常好并且通常会有一些状态"
-
当然,但是 1 和 2 只是指不可变(直到新的
param_type)状态,并且不要“真的”让operator()改变状态。我们关心的“一些内部状态”将是不依赖于param_type的状态——链接中的#3 案例。你的代码要做的就是维护对以前的operator()调用的任何链式依赖。简单的发行版不太可能有这样的依赖关系(即,它们的reset()不会做任何事情,而具有相同param_type的两个构造实例将是相同的)。 -
@deviantfan 如果我总是需要同一范围内的数字,我可以重用相同的分布。对于更改范围,我需要更改现有发行版的
param_type(这就像reset())或新发行版。使用相同的分布是可能的,但很复杂(请参阅问题的编辑)。
标签: c++ c++11 random distribution prng