导致这种奇怪的随机数生成器行为的原因是什么?

时间:2015-01-30 01:47:08

标签: r plyr rcpp

我试图为某些模拟研究制作一些可重复的示例,因此我使用set.seed从"随机"获得一致的结果。部分。但是,我注意到我有时会得到不同的结果。

我试图将其缩小到一个可重复性最小的示例,但似乎需要多个元素来触发错误。

这是应该发生的事情:

library(RcppExamples)

set.seed(1)
RcppRNGs(3)
#        rnorm         rt rpois
# 1 -0.6264538  1.5144787     1
# 2  0.1836433 -0.3536704     0
# 3 -0.8356286 11.4386179     1
rnorm(3)
# [1]  1.12493092 -0.04493361 -0.01619026

此代码似乎是激活错误的原因:

library(plyr)
S <- llply(1:100, function(.) Sys.sleep(1), .progress="text")
# |==========================                                        |  25%

请注意:

  1. 我已经击中&#34;停止&#34; llply完成前的按钮。
  2. 我知道您在这种情况下通常会使用rlply,但这并不会触发此错误。
  3. 现在发生了什么:

    set.seed(1)
    RcppRNGs(3)
    #        rnorm         rt rpois
    # 1 -0.6264538  1.5144787     1
    # 2  0.1836433 -0.3536704     0
    # 3 -0.8356286 11.4386179     1
    rnorm(3)
    # [1] -0.6264538  0.1836433 -0.8356286
    

    我应该得到与第一个例子中相同的结果,但是rnorm给了我不同的数字。

    问题似乎是Rcpp不再影响随机数种子:

    set.seed(1)
    rnorm(3)
    # [1] -0.6264538  0.1836433 -0.8356286
    

    鉴于此处的所有交互部分,我应该向谁提交错误报告?


    这是我的sessionInfo()输出:

    R version 3.1.2 (2014-10-31)
    Platform: x86_64-w64-mingw32/x64 (64-bit)
    
    locale:
    [1] LC_COLLATE=English_New Zealand.1252  LC_CTYPE=English_New Zealand.1252    LC_MONETARY=English_New Zealand.1252 LC_NUMERIC=C                        
    [5] LC_TIME=English_New Zealand.1252    
    
    attached base packages:
    [1] stats     graphics  grDevices utils     datasets  methods   base     
    
    other attached packages:
    [1] plyr_1.8.1         RcppExamples_0.1.6 Rcpp_0.11.3       
    
    loaded via a namespace (and not attached):
    [1] tools_3.1.2
    

1 个答案:

答案 0 :(得分:3)

llply下降到loop_apply,最终调用此函数:

// [[Rcpp::export]]
List loop_apply(int n, Function f) {
  List out(n);

  for(int i = 0; i < n; ++i) {
    out[i] = f(i + 1);
  }

  return out;
}

因此,作为Rcpp::export业务的一部分,我们接到enterRNGScope的电话

    // [[Rcpp::register]]
    unsigned long enterRNGScope() {
        if (RNGScopeCounter == 0) GetRNGstate();
        RNGScopeCounter++;
        return RNGScopeCounter ;
    }

loop_apply结束时,我们应该拨打exitRNGScope

    // [[Rcpp::register]]
    unsigned long exitRNGScope() {
        RNGScopeCounter--;
        if (RNGScopeCounter == 0) PutRNGstate();
        return RNGScopeCounter ;
    }

问题是,由于中断,我们永远不会访问exitRNGScope,因此当RcppRNGs调用enterRNGScope时,只需要认为不需要调用GetRNGstate所以种子处理不当。

也许loop_apply应该致电checkUserInterrupt,但我不确定这会完全解决问题。