生成伪随机16位整数

时间:2019-01-09 13:45:08

标签: c++ c++11 random mersenne-twister

我需要生成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中找到要求)。有吗

更新:我使用适当的初始化为发行版更新了代码示例。

2 个答案:

答案 0 :(得分:8)

您的方法确实是正确的方法。

数学上的论点很复杂(我将尝试研究一下论文),但是正确的做法是采用C ++标准库实现的梅森·Twister的最低有效位。

如果您对序列的质量有任何疑问,请通过顽固测试进行操作。

答案 1 :(得分:2)

考虑到OP的问题(重点是我的话),可能会有误解:

  

我在这里看到的问题是std :: mt19937产生32位无符号整数[…]。   这意味着静态转换已完成,并且分发只使用这32位整数中的最低有效部分

那不是它的工作方式。

以下是https://en.cppreference.com/w/cpp/numeric/random

中的引号
  

随机数库提供了生成随机数和   伪随机数。这些类包括:

     
  • 统一随机位生成器(URBG),[…];
  •   
  • 随机数分布(例如均匀分布,正态分布或泊松分布),可将URBG的输出转换为各种统计分布
     

URBG和分布旨在一起使用以产生随机值。

因此是统一的随机位生成器,例如mt19937random_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对其进行测试。