R replicate()函数不适用于Rcpp函数

时间:2018-05-26 14:15:21

标签: r rcpp replicate

我在使用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;
}

2 个答案:

答案 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的影响。在这种情况下,按时间种子是更好的选择。