[英]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: 所以我的问题是:
uint32
and mt19973
. uint32
和mt19973
类型和值来专门化其余代码。 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();
}
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.