简体   繁体   English

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

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

I am trying to reimplement c++11 uniform_int_distribution without templates and specifically for mt19937 , because I wanted to port functionality in this typical use case to other languages without template facility, and it would be nice to have a more readable version. 我试图在没有模板的情况下重新实现c ++ 11 uniform_int_distribution ,特别是对于mt19937 ,因为我想在这个典型用例中将功能移植到没有模板功能的其他语言,并且拥有更易读的版本会更好。 The difficulty from reading gcc implementation far exceeds what I expected from this mathematically simple conversion from one uniform distribution to another. 阅读gcc实现的难度远远超出了我从一个统一分布到另一个统一分布的数学上简单转换的预期。 (Yes, I know this is specializing the general, and I wouldn't gain new functionality from this practice) (是的,我知道这是专门针对将军的,我不会从这种做法中获得新的功能)

I looked into gcc 4.8.1 headers. 我查看了gcc 4.8.1标题。 The most used mt19937 class is a typedef: 最常用的mt19937类是typedef:

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

The code for uniform_int_distribution in gcc is heavily templated, and not very readable to me. gcc中uniform_int_distribution的代码非常模板化,对我来说不太可读。 I wonder how I can simplify/specialize that code to non-template code, just for the mt19937 case. 我想知道如何将代码简化/专门化为非模板代码,仅适用于mt19937案例。

The most relevant piece of code I found from 4.8.1/include/c++/bits/random.tcc is attached in the end (with double underscore __ removed for clarity). 我在4.8.1 / include / c ++ / bits / random.tcc中找到的最相关的代码段最后附加了(为清楚起见,删除了双下划线__ )。

I tried to specialize the code but wasn't very successful. 我试图专门化代码,但不是很成功。 For starter, I tried to figure out the range of mt19937: the min is 0, the max is (in random.h): 对于启动器,我试图找出mt19937的范围:min为0,max为(在random.h中):

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

, which involves complicated template programming that's not easily readable. ,涉及复杂的模板编程,不易读取。 I figured maybe it's better to ask than reverse engineer the templates. 我想也许最好问一下逆向工程模板。

So my questions are: 所以我的问题是:

  1. What' the range (max) for the specific type mt19937? 特定类型mt19937的范围(最大值)是多少?
  2. How to specialize the rest of the code with types and values specific to uint32 and mt19973 . 如何使用特定于uint32mt19973类型和值来专门化其余代码。

Thanks in advance. 提前致谢。

--- gcc 4.8.1 code for sampling from mt19937 to uniform_int_distribution --- --- 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 generates integers in [0,2^32-1]: mt19937在[0,2 ^ 32-1]中生成整数:

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

gives

    0
    4294967295

2. If I understand correctly, you want to specialise the template "by hand", but without figuring out exactly what uniform_int_distribution does? 2.如果我理解正确,你想“手工”专门化模板,但没有弄清楚uniform_int_distribution究竟是做什么的? Once you have mt19937 (eg, http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c ), generating uniformly distributed integers in a given range [low, high] is conceptually simple, but there are a few details that require attention (for example, meticulously checking for off-by-one errors). 一旦你有mt19937(例如, http//www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c ),在给定范围内生成均匀分布的整数[低,高]在概念上很简单,但有一些细节需要注意(例如,仔细检查一个一个错误)。 The second answer here Generating a uniform distribution of INTEGERS in C (after the accepted one) might be helpful. 第二个答案在C中生成INTEGERS的均匀分布 (在接受的之后)可能会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM