2014-10-20 70 views
7

我剛剛開始在R中使用Rcpp包,我的學習靈感來自Hadley Wickham的Advanced R課程。Rcpp可以替換R中的unif函數嗎?

在R studio中,我有以下.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++代碼運行得更有效率。我可能在這裏很幼稚,但是如果在性能上有這樣的差異,那麼爲什麼不是所有適用的R函數都用C++重寫?

看起來很明顯,有很多可能的改進,我覺得我錯過了一個巨大的原因,爲什麼不是所有的R函數都可以被盲目地複製到C++中以獲得性能。

編輯:對於這個例子,已經證明rand()的C++實現有些缺陷。我注意到的性能差距最多的是使用rand()函數。其他功能的表現看起來並不那麼激烈,所以我改變了問題的名稱。

+0

可能存在一些隨機數字狀態的存儲和檢索;我不知道'rand()'對此做了什麼... – 2014-10-20 13:13:44

+0

是否使用內置的Unix'rand()'? – 2014-10-20 13:25:42

+0

我並不瞭解C++,我只是從今天開始。我在stackoverflow上讀到使用rand()'''是得到我想要的東西的高性能方式,這就是爲什麼它以這種方式實現的原因。沒有線索,如果它是內置的Unix或不... – cantdutchthis 2014-10-20 13:28:49

回答

11

請不要使用rand()。如果你提交它,這樣做也會將你的軟件包從CRAN中刪除。

見例如this C++ reference page一個警告:

有沒有保證,而產生的隨機序列的質量。在過去,rand()的一些實現在產生的序列的隨機性,分佈和週期方面存在嚴重的缺陷(在一個衆所周知的例子中,低位簡單地在調用之間在1和0之間交替)。

如果你有興趣在備用隨機數發生器和時間,Rcpp Gallery

一般而言,使用由R提供的具有出色統計質量的生成器,並且由Rcpp以標量和向量化形式(「Rcpp Sugar」)提供。

+1

這真的是一個問題的答案「Rcpp可以替換R中的所有(或許多)函數嗎?」? (順便說一句,我會認爲答案只是「是」)。 – Spacedman 2014-10-20 15:23:02

+0

在「只要你不做任何傻事就像調用rand()'」那樣。但這真的只是重申圖靈等價。 – 2014-10-20 15:24:58

5

從R-3.1.1開始,runif使用.External接口,該接口複製其參數。 Luke Tierney將此更改爲使用R-devel中的.Call界面revision 66110.Call接口不會複製其參數。 Rcpp使用.Call接口。


在R-devel下(使用.Call接口),您的C++代碼仍然更快。這可能是因爲正在使用的隨機數發生器的差異。而且,R的函數通常比你編寫的任何專門的代碼有更多的檢查;這些檢查需要時間。