среднее значение в R CPP медленнее, чем среднее значение R - PullRequest
0 голосов
/ 12 января 2020

Заинтересованный в R cpp, я скопировал простой пример из «Продвинутого R» Хэдли Уикхема:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double meanC(NumericVector x) {
  int n = x.size();
  double total = 0;

  for(int i = 0; i < n; ++i) {
    total += x[i];
  }
  return total / n;
}

/*** R
library(microbenchmark)
x <- runif(1e5)
microbenchmark(
  mean(x),
  meanC(x)
)
*/

, который дает мне:

Unit: microseconds
     expr     min       lq     mean   median       uq      max neval cld
  mean(x) 149.412 161.4115 181.1470 180.3395 204.2910  216.656   100  a 
 meanC(x) 394.605 400.4335 489.2311 481.6755 539.6835 1425.628   100   b

Кажется, это означает C () значительно медленнее, чем среднее ()! Почему? Могу ли я что-нибудь сделать, чтобы ускорить, значит C?

Протестировано на macOS Catalina 64bit.

1 Ответ

4 голосов
/ 13 января 2020

Поскольку код в главном l oop для (ручной) mean() очень прост, настройки оптимизации имеют большое значение .

Если я применяю -O0 (и обратите внимание, что -g также используется):

R> microbenchmark(mean(x), meanC(x), meanS(x)
+ )
Unit: microseconds
     expr      min       lq     mean   median       uq     max neval cld
  mean(x)  653.089  654.093  693.971  670.952  708.419 1090.22   100 a  
 meanC(x) 1922.536 1951.835 2067.521 1980.786 2058.981 3078.64   100  b 
 meanS(x) 3409.202 3467.219 3660.131 3520.522 3618.264 5999.65   100   c
R> 

Если я использую -O1 или значение по умолчанию -O3, которое я обычно использую, я получаю по существу идентичные результаты. Вот -O3:

R> microbenchmark(mean(x), meanC(x), meanS(x)
+ )
Unit: microseconds
     expr     min      lq    mean  median      uq      max neval cld
  mean(x) 653.006 653.400 683.852 668.616 699.988  869.978   100   b
 meanC(x) 435.107 435.435 460.909 438.860 465.111 1078.962   100  a 
 meanS(x) 652.505 652.873 689.620 660.695 693.213 1270.513   100   b
R> 

Если я попытаюсь -O6 -march=native, я получу примерно то же самое. Не так уж много можно сделать, и компилятор, очевидно, достаточно хорош, чтобы добавить что-то стоящее даже при самых простых настройках.

Код ниже
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double meanC(NumericVector x) {
  int n = x.size();
  double total = 0;

  for(int i = 0; i < n; ++i) {
    total += x[i];
  }
  return total / n;
}

// [[Rcpp::export]]
double meanS(const Rcpp::NumericVector& x) {
  return Rcpp::mean(x);
}

/*** R
library(microbenchmark)
x <- runif(5e5)
microbenchmark(mean(x), meanC(x), meanS(x)
)
*/
...