C++ 使用RcppArmadillo计算向量的尾和

C++ 使用RcppArmadillo计算向量的尾和,c++,r,rcpp,rcpparmadillo,C++,R,Rcpp,Rcpparmadillo,我写了一个R代码来计算向量的尾和: tailsum <- function(x){ sum(x) + x - cumsum(x) } tailsum x microbenchmark( +尾和(x), +尾水_cpp(x), +泰尔苏姆阿玛(x) + ) 单位:微秒 expr最小lq平均uq最大neval cld 尾款(x)2.0 2.3 2.826 2.5 2.70 14.4 100 a 尾款_cpp(x)1.9 2.1 2.495 2.3 2.60 6.5 100 a tail

我写了一个R代码来计算向量的尾和:

tailsum <- function(x){
   sum(x) + x - cumsum(x)
}
tailsum x microbenchmark(
+尾和(x),
+尾水_cpp(x),
+泰尔苏姆阿玛(x)
+ )
单位:微秒
expr最小lq平均uq最大neval cld
尾款(x)2.0 2.3 2.826 2.5 2.70 14.4 100 a
尾款_cpp(x)1.9 2.1 2.495 2.3 2.60 6.5 100 a
tailsum_arma(x)2.2.4 3.128 2.6 2.85 30.4 100 a

如何改进用RcppArmadillo编写的代码?(我需要使用RcppArmadillo,因为还有许多其他线性代数操作是使用RcppArmadillo完成的。)

有趣的问题,体面的答案。我们可以进一步改进:

  • 为了防御性,我建议不要使用
    名称空间…
    并使用显式引用“只是为了确保”
  • 不需要包括Rcpp.h,RcppArmadillo.h做了我们所需要的一切(这是一个无操作)
  • 你的向量太小了,不重要,我拨到了1e4,1e5,1e6——然后犰狳有时会把R绑在一起,或者“在中间”以微弱优势击败它
  • 正如我们所看到的,“基本”R操作是对编译代码的直接和精简调用,因此您不必“击败它们”(除非您使用OpenMP和其他技巧)
  • 为什么不将tailsum_cpp和tailsum_self的两个循环合并到一个函数中,以节省调用开销——这是最快的结果
  • 尽管如此,我几乎总是选择你的第一种方法,在一行程序中使用犰狳函数
以下是我通过较小的更改和较大的向量以及更多的运行得到的结果:

Unit: milliseconds
  expr     min      lq    mean  median      uq     max neval cld
     r 3.09441 3.58882 7.46590 5.42797 6.79353 181.518   500   b
  rcpp 3.57488 4.16185 8.15100 5.83417 7.26449 146.467   500   b
  arma 3.09324 3.77172 7.63546 5.50456 8.21274 221.112   500   b
 combo 2.72539 2.87299 4.58357 3.16753 4.95350 109.923   500  a 
> 
代码如下
#包括
//[[Rcpp::depends(RcppArmadillo)]]
//[[Rcpp::导出]]
arma::colvec tailsum_arma(const arma::colvec&x){
返回arma::sum(x)+x-arma::cumsum(x);
}
Rcpp::NumericVector累积和自身(常量Rcpp::NumericVector&x){
自动x_len=x.length();
Rcpp::数值向量y(x_len);
y[0]=x[0];
对于(int i=1;itailsum\r你就不能把它写成一个循环吗?就像你为cumsum做的一样谢谢你!它真的有效!我非常依赖于图书馆的功能,我从来没有想过使用循环来完成这个简单的问题。@ F.PrvIEe感谢你的详细答案和有用的C++技巧,这对我帮助很大。Eddelbuettel@ChenHuang:不客气!请随意选择“向上投票”(点击向上三角形)和/或“接受”(点击勾号,只有你是提问者,请看),以表示答案有帮助/回答你的问题。这就是答案之间的信号和奖励。
> x <- rnorm(1000)
> microbenchmark(
+     tailsum(x),
+     tailsum_cpp(x),
+     tailsum_arma(x)
+ )
Unit: microseconds
            expr min  lq  mean median   uq  max neval cld
      tailsum(x) 2.0 2.3 2.826    2.5 2.70 14.4   100   a
  tailsum_cpp(x) 1.9 2.1 2.495    2.3 2.60  6.5   100   a
 tailsum_arma(x) 2.2 2.4 3.128    2.6 2.85 30.4   100   a
Unit: milliseconds
  expr     min      lq    mean  median      uq     max neval cld
     r 3.09441 3.58882 7.46590 5.42797 6.79353 181.518   500   b
  rcpp 3.57488 4.16185 8.15100 5.83417 7.26449 146.467   500   b
  arma 3.09324 3.77172 7.63546 5.50456 8.21274 221.112   500   b
 combo 2.72539 2.87299 4.58357 3.16753 4.95350 109.923   500  a 
> 
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::colvec tailsum_arma(const arma::colvec &x){
    return arma::sum(x) + x - arma::cumsum(x);
}

Rcpp::NumericVector cumsum_self(const Rcpp::NumericVector &x){
    auto x_len = x.length();
    Rcpp::NumericVector y(x_len);
    y[0] = x[0];
    for (int i = 1;i < x_len; i++){
        y[i] = y[i - 1] + x[i];
    }
    return y;
}

// [[Rcpp::export]]
Rcpp::NumericVector tailsum_cpp(const Rcpp::NumericVector &x){
    //just to compare with tailsum_arma
    return sum(x) + x - cumsum_self(x);
}

// [[Rcpp::export]]
Rcpp::NumericVector tailsum_combo(const Rcpp::NumericVector &x){
    size_t x_len = x.length();
    double x_sum = Rcpp::sum(x);
    double csum = 0.0;
    Rcpp::NumericVector y(x_len);
    for (size_t i = 0; i < x_len; i++) {
        csum += x[i];
        y[i] = x_sum - csum + x[i];
    }
    return y;
}

/*** R

# But to my surprise, R code is more efficient than RcppArmadillo code:

tailsum_r <- function(x){
   sum(x) + x - cumsum(x)
}

x <- rnorm(1e6)
microbenchmark::microbenchmark(r = tailsum_r(x),
                               rcpp = tailsum_cpp(x),
                               arma = tailsum_arma(x),
                               combo = tailsum_combo(x),
                               times = 500)

*/