2012-07-02 39 views
13

我通过inline提出在RCPP功能的第一个尝试,它解决了我的速度问题(感谢德克!): R: Replacing negative values by zeroRCPP通过引用传递与按值

最初的版本是这样的:

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 

我不是唯一一个谁试图复制这种行为,发现不一致的结果:

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

这是怎么回事吗?

+0

你能重新表达你的问题吗?你是否想要覆盖?在我看来,版本2实现了它所要做的事情......此外,还有一个致力于Rcpp的专用邮件列表,您可能会得到体面的答案。 –

+0

为了清晰起见,试图编辑。我不希望它被覆盖。如果这不明显,那么我想我应该发布到邮件列表,但不想打扰别人。 –

回答

18

它们的关键是'代理模式' - 您的xa确实与原始对象的内存位置相同,因此您最终会更改原始对象。

如果你不想这样做,你应该做一件事:使用clone()方法(深)复制,或者可能显式创建一个新的对象,其中写入更改的对象。方法二是而不是这样做,您只需使用两个不同名称的变量,它们都是“指针”(代理模型意义上的)与原始变量。

但是,当您将int矢量(从R)传递给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)) 

,这是我所看到的:

[email protected]:~/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 
[email protected]:~/svn/rcpp/pkg$ 

所以,真正的问题是否传递int-to-float或float-to-float。

+1

谢谢德克。这告诉我应该如何编写这个函数(我将把它提交以备将来使用)。我认为隐含的投射和复制可能会解释看似不一致的地方。 –

+1

当你第一次遇到它时,它是一个令人头疼的人,但是,它确实有道理。 –

+0

非常有趣。为了清楚起见,一个小小的错误:在每次函数调用之后都不应该重新定义 - 特别是第二次调用f1?否则,它是被改变的p被喂入f2 ...对吗? –