我需要生成16位伪随机整数,我想知道最好的选择是什么。
我想到的最明显的方式如下:
std::random_device rd;
auto seed_data = std::array<int, std::mt19937::state_size> {};
std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::mt19937 generator(seq);
std::uniform_int_distribution<short> dis(std::numeric_limits<short>::min(),
std::numeric_limits<short>::max());
short n = dis(generator);
我在这里看到的问题是std::mt19937
产生32位无符号整数,因为它是这样定义的:
using mt19937 = mersenne_twister_engine<unsigned int,
32, 624, 397,
31, 0x9908b0df,
11, 0xffffffff,
7, 0x9d2c5680,
15, 0xefc60000,
18, 1812433253>;
这意味着将完成静态转换,并且发行版仅使用这些32位整数中的最低有效部分。因此,我想知道这些伪随机短裤系列的效果如何,我没有数学专业知识来回答这个问题。
我希望更好的解决方案是对16位整数使用您自己定义的mersenne_twister_engine
引擎。但是,我还没有为模板参数找到任何提及的集合(例如,可以在here中找到要求)。有吗
更新:我使用适当的初始化为发行版更新了代码示例。
答案 0 :(得分:8)
您的方法确实是正确的方法。
数学上的论点很复杂(我将尝试研究一下论文),但是正确的做法是采用C ++标准库实现的梅森·Twister的最低有效位。
如果您对序列的质量有任何疑问,请通过顽固测试进行操作。
答案 1 :(得分:2)
考虑到OP的问题(重点是我的话),可能会有误解:
我在这里看到的问题是std :: mt19937产生32位无符号整数[…]。 这意味着静态转换已完成,并且分发只使用这32位整数中的最低有效部分。
那不是它的工作方式。
以下是https://en.cppreference.com/w/cpp/numeric/random
中的引号随机数库提供了生成随机数和 伪随机数。这些类包括:
- 统一随机位生成器(URBG),[…];
- 随机数分布(例如均匀分布,正态分布或泊松分布),可将URBG的输出转换为各种统计分布
URBG和分布旨在一起使用以产生随机值。
因此是统一的随机位生成器,例如mt19937
或random_device
是一个函数对象,它返回无符号整数值,以使可能结果范围内的每个值(理想地)具有相等的返回概率。
随机数分布,例如uniform_int_distribution
以这样的方式对URBG的输出进行后处理:根据定义的统计概率密度函数分配结果输出。
完成过程将使用源中的 all 位来产生输出。例如,我们可以看一下libstdc++
中std::uniform_distribution
的实现(从第824行开始),可以将其大致简化为
template <typename Type>
class uniform_distribution
{
Type a_ = 0, b_ = std::numeric_limits<Type>::max();
public:
uniform_distribution(Type a, Type b) : a_{a}, b_{b} {}
template<typename URBG>
Type operator() (URBG &gen)
{
using urbg_type = std::make_unsigned_t<typename URBG::result_type>;
using u_type = std::make_unsigned_t<Type>;
using max_type = std::conditional_t<(sizeof(urbg_type) > sizeof(u_type))
, urbg_type, u_type>;
urbg_type urbg_min = gen.min();
urbg_type urbg_max = gen.max();
urbg_type urbg_range = urbg_max - urbg_min;
max_type urange = b_ - a_;
max_type udenom = urbg_range <= urange ? 1 : urbg_range / (urange + 1);
Type ret;
// Note that the calculation may require more than one call to the generator
do
ret = (urbg_type(gen()) - urbg_min ) / udenom;
// which is 'ret = gen / 65535' with OP's parameters
// not a simple cast or bit shift
while (ret > b_ - a_);
return ret + a_;
}
};
可以HERE对其进行测试。