2012-10-22 43 views
6

我已經寫了一個函數「富」在C,我想從R程序調用。該函數接受一個矩陣作爲輸入,並對其執行一些操作(比如說,將每個元素加1)。雖然很容易在單個矢量R .C接口:傳遞多維數組

.C("foo", n=as.integer(5), x=as.double(rnorm(5))) 

以foo實現爲

void foo(int *nin, double *x) 
{ 
int n = nin[0]; 

int i; 

for (i=0; i<n; i++) 
    x[i] = x[i] * x[i]; 
} 

如何傳遞一個二維數組?如果我將「double * x」更改爲「double ** x」,則會出現分段錯誤。任何指針讚賞。

回答

7

沒有必要放棄在.C這樣的直接操作。請記住,R中的矩陣是一個向量+維度。同樣在C中,傳遞矩陣及其維數,並將矩陣的元素按照適當的偏移量存取到矢量中。像

void cplus1(double *x, int *dim) 
{ 
    for (int j = 0; j < dim[1]; ++j) 
     for (int i = 0; i < dim[0]; ++i) 
      x[j * dim[0] + i] += 1; 
} 

東西,所以使用inline作爲一個很好的聚會招

library(inline) 
sig <- signature(x="numeric", dim="integer") 
body <- " 
    for (int j = 0; j < dim[1]; ++j) 
     for (int i = 0; i < dim[0]; ++i) 
      x[j * dim[0] + i] += 1; 
" 

cfun <- cfunction(sig, body=body, language="C", convention=".C") 

plus1 <- function(m) { 
    m[] = cfun(as.numeric(m), dim(m))$x 
    m 
} 
+0

'.C'增加了複製參數去C程序的開銷時間,然後複製回結果,而'.Call'不 – transang

+0

@transang如果目標是_modify_從傳遞的對象R,那麼你必須用C複製它;您可以使用'.C()'自動安全地複製副本,或者使用'.Call()'手動執行並且發生錯誤的概率很高。 Rcpp方式也需要一個內存拷貝,在Dirk的回答中是'Rcpp :: clone(M)'語句。當然,Rcpp對於嚴肅的C級開發來說太棒了。 –

8

放棄.C()並切換到.Call(),它允許您將所有R對象作爲所謂的SEXP對象傳遞。

你可以通過R的C API或通過Rcpp(我們認爲的)更好的更高級別的抽象來解析這些困難的方式。

R> library(inline) # use version 0.3.10 for rcpp() wrapper 
R> 
R> addMat <- rcpp(signature(ms="numeric"), body=' 
+ Rcpp::NumericMatrix M(ms); 
+ Rcpp::NumericMatrix N = Rcpp::clone(M); 
+ for (int i=0; i<M.nrow(); i++) 
+  for (int j=0; j<M.ncol(); j++) 
+   N(i,j) = M(i,j) + 1; 
+ return(N); 
+ ') 
R> addMat(matrix(1:9,3,3)) 
    [,1] [,2] [,3] 
[1,] 2 5 8 
[2,] 3 6 9 
[3,] 4 7 10 
R> 
0

隨着.C,您必須通過額外的參數傳遞矩陣尺寸爲@馬丁摩根的答案。

隨着.Call

SEXP foo(SEXP mat){ 
    SEXP dims = getAttttrib(mat, R_DimSymbol); 
    int nrow = INTEGER(dims)[0]; 
    int ncol = INTEGER(dims)[1]; 
    //... 
} 
+0

不要忘記複製該矩陣! –