15

経由で Rcpp 関数を最初に突き刺したところinline、速度の問題が解決されました (Dirk に感謝します!): 負の値をゼロに置き換えます

初期バージョンは次のように見えました。

library(inline)
cpp_if_src <- '
  Rcpp::NumericVector xa(a);
  int n_xa = xa.size();
  for(int i=0; i < n_xa; i++) {
    if(xa[i]<0) xa[i] = 0;
  }
  return xa;
'
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")

しかし、呼び出されると、出力がcpp_if(p)上書きされ、意図したとおりではありませんでした。pしたがって、参照渡しであると想定しました。

そのため、次のバージョンで修正しました。

library(inline)
cpp_if_src <- '
  Rcpp::NumericVector xa(a);
  int n_xa = xa.size();
  Rcpp::NumericVector xr(a);
  for(int i=0; i < n_xa; i++) {
    if(xr[i]<0) xr[i] = 0;
  }
  return xr;
'
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")

これはうまくいったようです。しかし、元のバージョンを R に再ロードしても、元のバージョンは入力を上書きしなくなりました (つまり、まったく同じコードが入力を上書きしなくなりました)。

> cpp_if_src <- '
+   Rcpp::NumericVector xa(a);
+   int n_xa = xa.size();
+   for(int i=0; i < n_xa; i++) {
+     if(xa[i]<0) xa[i] = 0;
+   }
+   return xa;
+ '
> cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
> 
> p
 [1] -5 -4 -3 -2 -1  0  1  2  3  4  5
> cpp_if(p)
 [1] 0 0 0 0 0 0 1 2 3 4 5
> p
 [1] -5 -4 -3 -2 -1  0  1  2  3  4  5

この動作を再現しようとして一貫性のない結果が得られたのは私だけではありません。

https://chat.stackoverflow.com/transcript/message/4357344#4357344

何が起きてる?

4

1 に答える 1

21

それらの鍵は「プロキシモデル」です。xa実際には元のオブジェクトと同じメモリの場所であるため、元のオブジェクトを変更することになります。

それが望ましくない場合は、clone()メソッドを使用して (ディープ) コピーするか、変更されたオブジェクトが書き込まれる新しいオブジェクトを明示的に作成する必要があります。方法 2 はそれを行いませ。元の変数への (プロキシ モデルの意味で) どちらも「ポインター」である 2 つの異なる名前の変数を使用するだけです。

ただし、(R からの) int ベクトルを NumericVector 型に渡す場合、暗黙的なキャストとコピーがさらに複雑になります。これにより、コピーが作成され、元のものが変更されなくなります。

チュートリアルやワークショップで使用したものと同様の、より明確な例を次に示します。

library(inline)
f1 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
  Rcpp::NumericVector xa(a);
  int n = xa.size();
  for(int i=0; i < n; i++) {
    if(xa[i]<0) xa[i] = 0;
  }
  return xa;
')

f2 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
  Rcpp::NumericVector xa(a);
  int n = xa.size();
  Rcpp::NumericVector xr(a);            // still points to a
  for(int i=0; i < n; i++) {
    if(xr[i]<0) xr[i] = 0;
  }
  return xr;
')

p <- seq(-2,2)
print(class(p))
print(cbind(f1(p), p))
print(cbind(f2(p), p))
p <- as.numeric(seq(-2,2))
print(class(p))
print(cbind(f1(p), p))
print(cbind(f2(p), p))

これは私が見るものです:

edd@max:~/svn/rcpp/pkg$ r /tmp/ari.r
Loading required package: methods
[1] "integer"
        p
[1,] 0 -2
[2,] 0 -1
[3,] 0  0
[4,] 1  1
[5,] 2  2
        p
[1,] 0 -2
[2,] 0 -1
[3,] 0  0
[4,] 1  1
[5,] 2  2
[1] "numeric"
       p
[1,] 0 0
[2,] 0 0
[3,] 0 0
[4,] 1 1
[5,] 2 2
       p
[1,] 0 0
[2,] 0 0
[3,] 0 0
[4,] 1 1
[5,] 2 2
edd@max:~/svn/rcpp/pkg$

したがって、int-to-float を渡すか、float-to-float を渡すかは非常に重要です。

于 2012-07-02T20:28:52.890 に答える