为<;创建PRNG引擎;随机>;在C++;11匹配PRNG的结果为R
这个问题有两个方面。我将R脚本翻译成C++,使用L'ECu耶组合多递归发生器(CMRG)作为它的引擎(特别是MRG32 K3A),然后在间隔(0, 1)上从均匀分布返回随机数。R中的最小示例如下所示:为<;创建PRNG引擎;随机>;在C++;11匹配PRNG的结果为R,r,c++11,random,R,C++11,Random,这个问题有两个方面。我将R脚本翻译成C++,使用L'ECu耶组合多递归发生器(CMRG)作为它的引擎(特别是MRG32 K3A),然后在间隔(0, 1)上从均匀分布返回随机数。R中的最小示例如下所示: seednum<-100 # set seed set.seed(seednum, kind="L'Ecuyer-CMRG") # set RNG engine runif(1)
seednum<-100 # set seed
set.seed(seednum, kind="L'Ecuyer-CMRG") # set RNG engine
runif(1) # set distribution
/*
32-bits Random number generator U(0,1): MRG32k3a
Author: Pierre L'Ecuyer,
Source: Good Parameter Sets for Combined Multiple Recursive Random
Number Generators,
Shorter version in Operations Research,
47, 1 (1999), 159--164.
---------------------------------------------------------
*/
#include <stdio.h>
#define norm 2.328306549295728e-10
#define m1 4294967087.0
#define m2 4294944443.0
#define a12 1403580.0
#define a13n 810728.0
#define a21 527612.0
#define a23n 1370589.0
/***
The seeds for s10, s11, s12 must be integers in [0, m1 - 1] and not all 0.
The seeds for s20, s21, s22 must be integers in [0, m2 - 1] and not all 0.
***/
#define SEED 100
static double s10 = SEED, s11 = SEED, s12 = SEED,
s20 = SEED, s21 = SEED, s22 = SEED;
double MRG32k3a (void)
{
long k;
double p1, p2;
/* Component 1 */
p1 = a12 * s11 - a13n * s10;
k = p1 / m1;
p1 -= k * m1;
if (p1 < 0.0)
p1 += m1;
s10 = s11;
s11 = s12;
s12 = p1;
/* Component 2 */
p2 = a21 * s22 - a23n * s20;
k = p2 / m2;
p2 -= k * m2;
if (p2 < 0.0)
p2 += m2;
s20 = s21;
s21 = s22;
s22 = p2;
/* Combination */
if (p1 <= p2)
return ((p1 - p2 + m1) * norm);
else
return ((p1 - p2) * norm);
}
int main()
{
double result = MRG32k3a();
printf("Result with seed 100 is: %f\n", result);
return (0);
}
结果随机数为0.671156
。我最初对这个结果感到困惑,但之前的问题为我澄清了这一点(如上链接)。看来,R中有参数传递给MRG32 K3A,我需要在C++中复制,以便生成相同的随机数。因此,第一个问题是,我在哪里可以找到在R中指定这些参数的MRG32k3a实现的文档
第二个问题涉及在C++11中实现此生成器。此生成器不出现在所列C++11的
库中预先配置的发动机类型列表中。可以找到用C实现的MRG32k3a示例,如下所示:
seednum<-100 # set seed
set.seed(seednum, kind="L'Ecuyer-CMRG") # set RNG engine
runif(1) # set distribution
/*
32-bits Random number generator U(0,1): MRG32k3a
Author: Pierre L'Ecuyer,
Source: Good Parameter Sets for Combined Multiple Recursive Random
Number Generators,
Shorter version in Operations Research,
47, 1 (1999), 159--164.
---------------------------------------------------------
*/
#include <stdio.h>
#define norm 2.328306549295728e-10
#define m1 4294967087.0
#define m2 4294944443.0
#define a12 1403580.0
#define a13n 810728.0
#define a21 527612.0
#define a23n 1370589.0
/***
The seeds for s10, s11, s12 must be integers in [0, m1 - 1] and not all 0.
The seeds for s20, s21, s22 must be integers in [0, m2 - 1] and not all 0.
***/
#define SEED 100
static double s10 = SEED, s11 = SEED, s12 = SEED,
s20 = SEED, s21 = SEED, s22 = SEED;
double MRG32k3a (void)
{
long k;
double p1, p2;
/* Component 1 */
p1 = a12 * s11 - a13n * s10;
k = p1 / m1;
p1 -= k * m1;
if (p1 < 0.0)
p1 += m1;
s10 = s11;
s11 = s12;
s12 = p1;
/* Component 2 */
p2 = a21 * s22 - a23n * s20;
k = p2 / m2;
p2 -= k * m2;
if (p2 < 0.0)
p2 += m2;
s20 = s21;
s21 = s22;
s22 = p2;
/* Combination */
if (p1 <= p2)
return ((p1 - p2 + m1) * norm);
else
return ((p1 - p2) * norm);
}
int main()
{
double result = MRG32k3a();
printf("Result with seed 100 is: %f\n", result);
return (0);
}
/*
32位随机数发生器U(0,1):MRG32k3a
作者:Pierre L'Ecuyer,
来源:组合多重递归随机变量的良好参数集
数字发生器,
运筹学的较短版本,
47, 1 (1999), 159--164.
---------------------------------------------------------
*/
#包括
#定义规范2.328306549295728e-10
#定义m1 4294967087.0
#定义m2 42944443.0
#定义a12 1403580.0
#定义a13n 810728.0
#定义a21 527612.0
#定义a23n 1370589.0
/***
s10、s11、s12的种子必须是[0,m1-1]中的整数,而不是全部为0。
s20、s21、s22的种子必须是[0,m2-1]中的整数,而不是全部为0。
***/
#定义种子100
静态双s10=种子,s11=种子,s12=种子,
s20=种子,s21=种子,s22=种子;
双MRG32k3a(无效)
{
长k;
双p1,p2;
/*组成部分1*/
p1=a12*s11-a13n*s10;
k=p1/m1;
p1-=k*m1;
如果(p1<0.0)
p1+=m1;
s10=s11;
s11=s12;
s12=p1;
/*构成部分2*/
p2=a21*s22-a23n*s20;
k=p2/m2;
p2-=k*m2;
如果(p2<0.0)
p2+=m2;
s20=s21;
s21=s22;
s22=p2;
/*组合*/
如果(p1
因此,第一个问题是,我在哪里可以找到在R中指定这些参数的MRG32k3a实现的文档
我将使用以下来源:
问题是我不知道这是如何做到的,而且我似乎在任何地方都找不到任何信息(除了知道引擎是类之外)
RandomNumberEngine的要求可在此处找到:
虽然如果您想使用统一的真实分布,就足以满足以下要求:
Expression Return type Requirements
G::result_type T T is an unsigned integer type
G::min() T Returns the smallest value that G's operator()
may return. The value is strictly less than
G::max().
G::max() T Returns the largest value that G's operator() may
return. The value is strictly greater than
G::min()
g() T Returns a value in the closed interval [G::min(),
G::max()]. Has amortized constant complexity.
主要问题是MRG32 K3A是返回(0,1)中的浮点数,而C++统一随机比特生成器返回整数类型。为什么要与<代码>头?< /P>集成?
您必须考虑的其他困难:
- R,c.f.使用的播种策略
- R将用户提供的种子c.f.置乱
替代方法包括直接使用R源代码,而不与
标题集成或链接到libR
我发现在不同语言中具有相同种子的PRNG不一定产生相同的结果(因为它们可能有编译器可以自由指定的参数)如SO帖子和中所示。也就是说,根据PRNG的具体实现,使用相同的种子、相同的引擎和相同的分布可能会导致不同的随机数
第一个答案仅仅解释了不存在与给定的PRNG种子普遍对应的随机数序列;它可能在不同的API中以不同的方式记录和实现(不仅仅是在编译器中,也不仅仅是在语言级别).第二个答案是针对C语言中的rand
和srand
的,原因是
虽然两个答案都不涉及随机数分布,但如果需要可再现的“随机性”,它们也是重要的。在这个意义上,尽管C++保证了它提供的引擎的行为,但它使得
一般来说,如果使用一种稳定(不变)且记录在案的算法不仅用于已播种的PRNG,而且用于使用该PRNG的任何随机数方法(在R的情况下,包括runif
和rnorm
),则可以避免涉及可重复“随机性”的PRNG播种问题-在后一种情况下,因为“随机”序列的再现性取决于这些方法(不仅仅是PRNG本身)的记录方式
根据您是否编写了R代码,一个选项可以是写C++和R代码(如你似乎已经做了自己的部分),并使用自定义实现的算法来使用原来的R代码使用的每个随机数方法(例如<代码> RunIF <代码>和<代码> RAMNOR> <代码>)。此选项可能是可行的,尤其是因为统计测试通常对使用的特定PRNG的细节不敏感
根据R脚本的编写方式,另一个选项可能是预生成代码所需的随机数。为什么不使用R源代码的实现?