c++11随机数生成:如何在没有模板的情况下用' mt19937 '重新实现' uniform_int_distr

c++11 random number generation: how to re-implement `uniform_int_distribution` with `mt19937` without templates

本文关键字:新实现 mt19937 实现 distr int uniform 随机数 情况下 c++11      更新时间:2023-10-16

我正在尝试重新实现没有模板的c++11 uniform_int_distribution,特别是mt19937,因为我想将这个典型用例中的功能移植到没有模板设施的其他语言中,如果有一个更可读的版本就太好了。阅读gcc实现的难度远远超出了我对从一种均匀分布到另一种均匀分布的简单数学转换的预期。(是的,我知道这是专门化的,我不会从这个实践中获得新的功能)

我查看了gcc 4.8.1头文件。最常用的mt19937类是typedef:

  typedef mersenne_twister_engine<
    uint_fast32_t,
    32, 624, 397, 31,
    0x9908b0dfUL, 11,
    0xffffffffUL, 7,
    0x9d2c5680UL, 15,
    0xefc60000UL, 18, 1812433253UL> mt19937;

gcc中uniform_int_distribution的代码是大量模板化的,对我来说不是很好读。我想知道如何简化/专门化该代码为非模板代码,只是为了mt19937的情况。

我从4.8.1/include/c++/bits/random找到的最相关的代码。tcc附加在末尾(为了清晰起见,删除了双下划线__)。

我试图专门化代码,但不是很成功。对于初学者,我试图找出mt19937的范围:最小值为0,最大值为(在random.h中):

  static constexpr result_type
  max()
  { return __detail::_Shift<_UIntType, __w>::__value - 1; }

,它涉及复杂的模板编程,不容易阅读。我想也许直接问总比逆向工程模板好。

我的问题是:

  1. 特定型号mt19937的范围(最大值)是多少?
  2. 如何使用特定于uint32mt19973的类型和值专门化其余代码。

提前感谢。

——GCC 4.8.1从mt19937到uniform_int_distribution的抽样代码——

  template<typename _IntType>
    template<typename _ForwardIterator,
         typename _UniformRandomNumberGenerator>
      void
      uniform_int_distribution<_IntType>::
      generate_impl(_ForwardIterator f, _ForwardIterator t,
              _UniformRandomNumberGenerator& urng,
              const param_type& param)
      {
    glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>)
    typedef typename _UniformRandomNumberGenerator::result_type
      _Gresult_type;
    typedef typename std::make_unsigned<result_type>::type utype;
    typedef typename std::common_type<_Gresult_type, utype>::type
      uctype;
    const uctype urngmin = urng.min();
    const uctype urngmax = urng.max();
    const uctype urngrange = urngmax - urngmin;
    const uctype urange
      = uctype(param.b()) - uctype(param.a());
    uctype ret;
    if (urngrange > urange)
      {
        if (detail::_Power_of_2(urngrange + 1)
        && detail::_Power_of_2(urange + 1))
          {
        while (f != t)
          {
            ret = uctype(urng()) - urngmin;
            *f++ = (ret & urange) + param.a();
          }
          }
        else
          {
        // downscaling
        const uctype uerange = urange + 1; // urange can be zero
        const uctype scaling = urngrange / uerange;
        const uctype past = uerange * scaling;
        while (f != t)
          {
            do
              ret = uctype(urng()) - urngmin;
            while (ret >= past);
            *f++ = ret / scaling + param.a();
          }
          }
      }
    else if (urngrange < urange)
      {
        // upscaling
        /*
          Note that every value in [0, urange]
          can be written uniquely as
          (urngrange + 1) * high + low
          where
          high in [0, urange / (urngrange + 1)]
          and
          low in [0, urngrange].
        */
        uctype tmp; // wraparound control
        while (f != t)
          {
        do
          {
            const uctype uerngrange = urngrange + 1;
            tmp = (uerngrange * operator()
                 (urng, param_type(0, urange / uerngrange)));
            ret = tmp + (uctype(urng()) - urngmin);
          }
        while (ret > urange || ret < tmp);
        *f++ = ret;
          }
      }
    else
      while (f != t)
        *f++ = uctype(urng()) - urngmin + param.a();
      }
  1. mt19937生成整数[0,2^32-1]:

    std::mt19937 mt_gen;
    std::cout << mt_gen.min() << 'n';
    std::cout << mt_gen.max() << 'n';
    

    0
    4294967295

2。如果我理解正确的话,您想"手工"专门化模板,但没有弄清楚uniform_int_distribution到底是做什么的?一旦有了mt19937(例如http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c),在给定的[low, high]范围内生成均匀分布的整数在概念上很简单,但是有一些细节需要注意(例如,仔细检查偏离1的错误)。这里的第二个答案是在C中生成整数的统一分布(在可接受的分布之后)可能会有帮助。