c ++ 11随机数生成:如何使用`mt19937`重新实现`uniform_int_distribution`而不使用模板

时间:2014-03-20 03:18:27

标签: c++ templates gcc c++11 random

我正在尝试重新实现没有模板的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的范围:min为0,max为(在random.h中):

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

,涉及复杂的模板编程,不易阅读。我想也许最好问一下逆向工程模板。

所以我的问题是:

  1. 特定类型mt19937的范围(最大值)是什么?
  2. 如何使用特定于uint32mt19973的类型和值来专门化其余代码。
  3. 提前致谢。

    --- 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 个答案:

答案 0 :(得分:2)

  1. mt19937在[0,2 ^ 32-1]中生成整数:

    std::mt19937 mt_gen;
    std::cout << mt_gen.min() << '\n';
    std::cout << mt_gen.max() << '\n';
    
  2. 给出

        0
        4294967295
    

    2。如果我理解正确,你想专门化模板&#34;手工&#34;,但没有弄清楚uniform_int_distribution究竟是做什么的?一旦你有mt19937(例如,http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c),在给定范围[低,高]中生成均匀分布的整数在概念上很简单,但是有一些细节需要注意(例如,仔细检查旁路 - 一个错误)。这里的第二个答案Generating a uniform distribution of INTEGERS in C(在接受的答案之后)可能会有所帮助。