Rcpp能代替R中的unif函数吗

Can Rcpp replace unif function in R?

本文关键字:unif 函数 中的 Rcpp      更新时间:2023-10-16

我刚刚开始在R中使用Rcpp包,我的学习灵感来自Hadley Wickham的高级R课程。

在R工作室中,我有以下.cpp文件。这个问题比较笼统,但这个例子有帮助。

#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector runifC(int n, double min=0, double max=1) {
  NumericVector out(n);
  for(int i = 0; i < n; ++i) {
    out[i] = min + ((double) rand() / (RAND_MAX)) * (max - min);
  }
  return out;
}
/*** R
library(microbenchmark)
microbenchmark(
  'R unif-1'      = runif(1),
  'C++ unif-1'    = runifC(1),
  'R unif-100'    = runif(100),
  'C++ unif-100'  = runifC(100),
  'R unif-1000'   = runif(1000),
  'C++ unif-1000' = runifC(1000),
  'R unif-100000'   = runif(100000),
  'C++ unif-100000' = runifC(100000)
)
*/

当我获取/保存文件时,它会向我显示性能输出。

Unit: nanoseconds
             expr     min        lq       mean    median        uq     max neval
         R unif-1    2061    2644.5    4000.71    3456.0    4297.0   15402   100
       C++ unif-1     710    1190.0    1815.11    1685.0    2168.5    5776   100
       R unif-100    4717    5566.5    6794.14    6563.0    7435.5   16600   100
     C++ unif-100    1450    1997.5    2663.29    2591.5    3107.0    5307   100
      R unif-1000   28210   29584.5   31310.54   30380.0   31599.0   52879   100
    C++ unif-1000    8292    8951.0   10113.78    9462.5   10121.5   25099   100
    R unif-100000 2642581 2975117.0 3104580.62 3030938.5 3119489.0 5435046   100
  C++ unif-100000  699833  990924.0 1058855.49 1034430.5 1075078.0 1530351   100

我预计runif将是一个非常优化的函数,但C++代码的运行效率要高得多。我在这里可能很天真,但如果性能上有这样的差异,那么为什么不用C++重写所有适用的R函数呢?

很明显,有很多可能的改进,我觉得我错过了一个巨大的原因,为什么不是所有的R函数都可以盲目地复制到C++中以提高性能。

edit:对于这个例子,已经表明rand()的C++实现有一些缺陷。我最注意到的性能差距使用了CCD_ 4函数。其他功能的性能似乎没有那么激烈,所以我更改了问题的名称。

请不要使用rand()。如果你提交的话,这样做也会让你的包裹从CRAN上掉下来。

如需警告,请参阅本C++参考页:

票据

对于所产生的随机序列的质量没有任何保证。在过去,rand()的一些实现在产生的序列的随机性、分布和周期方面存在严重缺陷(在一个众所周知的例子中,低阶比特在调用之间只是在1和0之间交替)。

如果您对备用随机数生成器和计时感兴趣,请访问Rcpp库。

通常,使用R提供的生成器,这些生成器具有良好的统计质量,并由Rcpp以标量和矢量形式("Rcpp Sugar")提供。

从R-3.1.1开始,runif使用.External接口,该接口复制其参数。Luke Tierney在66110版本中将其更改为使用R-devel中的.Call接口。.Call接口不复制其参数。Rcpp使用.Call接口。


您的C++代码在R-devel下(使用.Call接口)仍然更快。这可能是因为所使用的随机数生成器存在差异。此外,R的函数通常比您编写的任何专用代码都有更多的检查;而这些检查需要时间。