Rcppインターフェイスを使ったクラスライブラリを作成するコード側で,たとえば
Rから受け取った SEXP 型 a は,以下のように Rcpp::RObjectクラスの派生クラスに変換する必要があるのだが,
Rcpp::NumericVector xa(a);
この xa はそのまま演算できる.
RcppExport SEXP convolve3cpp(SEXP a, SEXP b) {
Rcpp::NumericVector xa(a);
Rcpp::NumericVector xb(b);
int n_xa = xa.size(), n_xb = xb.size();
int nab = n_xa + n_xb - 1;
Rcpp::NumericVector xab(nab);
for (int i = 0; i < n_xa; i++)
for (int j = 0; j < n_xb; j++)
xab[i + j] += xa[i] * xb[j];
return xab;
}
これをRに返す際には,明示的に型変換する必要がないので,ついつい SEXP そのものだと誤解しそうになるが,あくまで
Rcpp::RObjectクラスのオブジェクトであることを忘れないようにしないと,妙な代入などをおこなってしまいそうになる.
ちなみに,伝統的な R API で,Rinternals.h を使う場合は,演算処理のためにポインタをとる.
SEXP convolve2(SEXP a, SEXP b)
{
R_len_t i, j, na, nb, nab;
double *xa, *xb, *xab;
SEXP ab;
// 型を指定して保護
PROTECT(a = coerceVector(a, REALSXP));
PROTECT(b = coerceVector(b, REALSXP));
na = length(a); nb = length(b); nab = na + nb - 1;
PROTECT(ab = allocVector(REALSXP, nab));
// C言語での演算のためポインタを取得
xa = REAL(a); xb = REAL(b);
xab = REAL(ab);
for(i = 0; i < nab; i++) xab[i] = 0.0;
for(i = 0; i < na; i++)
for(j = 0; j < nb; j++) xab[i + j] += xa[i] * xb[j];
UNPROTECT(3);
//SEXP型なのでそのまま返却できる
return(ab);
}
Rdefines.h を使う場合も,演算処理のためにポインタをとる.
SEXP convolve2(SEXP a, SEXP b)
{
R_len_t i, j, na, nb, nab;
double *xa, *xb, *xab;
SEXP ab;
// 数値型として保護し
PROTECT(a = AS_NUMERIC(a));
PROTECT(b = AS_NUMERIC(b));
na = LENGTH(a); nb = LENGTH(b); nab = na + nb - 1;
PROTECT(ab = NEW_NUMERIC(nab));
// Cの演算のためにポインタを取り出す
xa = NUMERIC_POINTER(a); xb = NUMERIC_POINTER(b);
xab = NUMERIC_POINTER(ab);
// ポインタを通した計算
for(i = 0; i < nab; i++) xab[i] = 0.0;
for(i = 0; i < na; i++)
for(j = 0; j < nb; j++) xab[i + j] += xa[i] * xb[j];
UNPROTECT(3);
// SEXP型なのでそのまま返却できる
return(ab);
}
と明示的にPROTECTが必要になる.