我在使用R中的replicate()
函数生成具有Rcpp函数的随机数时遇到问题。考虑R中的以下函数:
trial <- function(){rnorm(1)}
replicate(10, trial())
它从高斯分布生成10个随机数。它完全正常,并产生如下结果:
[1] 0.7609912 -0.2949613 1.8684363 -0.3358377 -1.6043926 0.2706250 0.5528813 1.0228125 -0.2419092 -1.4761937
但是,我有一个c ++函数getRan()
,可以从高斯分布中生成一个随机数。我再次使用replicate来调用这个函数:
replicate(10,getRan())
它创建一个相同数字的向量,如下所示:
> replicate(10,getRan())
[1] -1.374932 -1.374932 -1.374932 -1.374932 -1.374932 -1.374932 -1.374932 -1.374932 -1.374932 -1.374932
> replicate(10,getRan())
[1] -0.3273785 -0.3273785 -0.3273785 -0.3273785 -0.3273785 -0.3273785 -0.3273785 -0.3273785 -0.3273785 -0.3273785
> replicate(10,getRan())
[1] -0.7591953 -0.7591953 -0.7591953 -0.7591953 -0.7591953 -0.7591953 -0.7591953 -0.7591953 -0.7591953 -0.7591953
> replicate(10,getRan())
[1] -1.698935 -1.698935 -1.698935 -1.698935 -1.698935 -1.698935 -1.698935 -1.698935 -1.698935 -1.698935
但是,如果我多次调用该函数,它可以正常工作:
getRan()
[1] 1.345227
> getRan()
[1] 0.3555393
> getRan()
[1] 1.587241
> getRan()
[1] 0.5313518
那么这里有什么问题? replicate()
函数是否从getRan()
重复相同的函数返回,而不是多次调用getRan()
?这是一个错误吗?
PS:我知道我可以使用rnorm(n)
生成n个正常随机数,但是,我想使用c ++函数根据生成随机数进行更复杂的计算
PPS:这是我的c ++代码:
double getRan(){
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
std::normal_distribution<double> distribution (0.0,1.0);
double epi = distribution(generator);
return epi;
}
答案 0 :(得分:2)
这是一个反例,显示它工作正常:
trialR <- function() { rnorm(1) }
Rcpp::cppFunction("double trialC() { return R::rnorm(0.0, 1.0); }")
Rcpp::cppFunction("Rcpp::NumericVector trialSugar() { return Rcpp::rnorm(1.0, 0.0, 1.0); }")
set.seed(123); replicate(3, trialR())
set.seed(123); replicate(3, trialC())
set.seed(123); replicate(3, trialSugar())
通过Rscript
确保新会议等pp:
edd@rob:/tmp$ Rscript so50543659.R
[1] -0.560476 -0.230177 1.558708
[1] -0.560476 -0.230177 1.558708
[1] -0.560476 -0.230177 1.558708
edd@rob:/tmp$
答案 1 :(得分:1)
德克斯的回答是正确的。你应该使用R的RNG。如果你坚持在C ++中使用RNG,你可以使用这样的东西:
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
#include <random>
namespace {
std::default_random_engine generator(std::random_device{}());
std::normal_distribution<double> distribution (0.0,1.0);
}
// [[Rcpp::export]]
double getRan(){
return distribution(generator);
}
/*** R
replicate(10,getRan())
*/
这可以避免在每次函数调用时创建std::default_random_engine
(和std::normal_distribution
)的新实例。这很重要,因为RNG的属性仅保证从一个RNG重复抽取。不是来自不同RNG的重复抽取,这些RNG播种(希望是不同的)种子。
std::random_device
的问题且正在使用Windows,则可能会受到this mingw bug的影响。在这种情况下,按时间种子是更好的选择。