RCPP 中的均值比 R 均值慢
mean in RCPP slower than R mean
对 Rcpp 感兴趣,我从 Hadley Wickham 那里复制了一个简单的例子 "Advanced 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
meanC() 似乎比 mean() 慢得多!为什么?
我可以做些什么来加速 meanC 吗?
在 macOS Catalina 64 位上测试。
因为(手动)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)
)
*/
对 Rcpp 感兴趣,我从 Hadley Wickham 那里复制了一个简单的例子 "Advanced 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
meanC() 似乎比 mean() 慢得多!为什么? 我可以做些什么来加速 meanC 吗?
在 macOS Catalina 64 位上测试。
因为(手动)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)
)
*/