当我比较R中本地Gamma函数gamma
与c++等效std::tgamma
的速度时,我发现后者大约慢10-15倍。为什么?我知道会有一些不同,但这很重要,不是吗?
我实现:
library("Rcpp")
library("microbenchmark")
cppFunction("
double gammacpp(double x) {
return(std::tgamma(x));
}
")
x = max(0, rnorm(1, 50, 25))
microbenchmark(gamma(x), gammacpp(x))
结果在我的机器上:
Unit: nanoseconds
expr min lq mean median uq max neval cld
gamma(x) 100 101 124.91 101 102 1001 100 a
gammacpp(x) 1000 1101 1302.98 1200 1300 9401 100 b
看gamma()
的代码(例如输入gamma<Return>
):它只是调用一个原语。
您的Rcpp
函数设置为方便。只需要两句话。但是它有一些开销,比如保存随机数生成器的状态,设置try
/catch
块进行异常处理等等。我们已经记录了如何跳过这些步骤中的一些,但在许多情况下,这是不明智的。
简而言之,我的观点是你选择了一个糟糕的比较:在你基准测试的函数中发生的事情太少了。还要注意单位:纳秒。你这里有很多测量误差。
但是鼓舞人心的是,用一个"幼稚的"(和方便的)c++函数作为你写的一行代码,你不会打败一些优化和调优的,并且已经从R中编译了代码。这实际上是一件好事,因为如果你这样做,你现在将不得不重写大量的R。
Edit:For kicks,这里是第三个变体'in middle',我们使用Rcpp
调用r的相同C API。
#include <Rcpp.h>
// [[Rcpp::export]]
double gammaStd(double x) { return (std::tgamma(x)); }
// [[Rcpp::export]]
Rcpp::NumericVector gamma_R(Rcpp::NumericVector x) { return (Rcpp::gamma(x)); }
/*** R
set.seed(123)
x <- max(0, rnorm(1, 50, 25))
res <- microbenchmark::microbenchmark(R = gamma(x), Cpp = gammaStd(x), Sugar = gamma_R(x) )
res
*/
> Rcpp::sourceCpp("~/git/stackoverflow/72383007/answer.cpp")
> set.seed(123)
> x <- max(0, rnorm(1, 50, 25))
> res <- microbenchmark::microbenchmark(R = gamma(x), Cpp = gammaStd(x), Sugar = gamma_R(x) )
>
res
Unit: nanoseconds
expr min lq mean median uq max neval cld
R 102 112.0 136.95 124 134.5 1068 100 a
Cpp 1111 1155.5 11930.02 1186 1260.0 1054813 100 a
Sugar 1142 1201.0 6355.92 1246 1301.5 506628 100 a
>
#include <Rcpp.h>
// [[Rcpp::export]]
double gammaStd(double x) { return (std::tgamma(x)); }
// [[Rcpp::export]]
Rcpp::NumericVector gamma_R(Rcpp::NumericVector x) { return (Rcpp::gamma(x)); }
/*** R
set.seed(123)
x <- max(0, rnorm(1, 50, 25))
res <- microbenchmark::microbenchmark(R = gamma(x), Cpp = gammaStd(x), Sugar = gamma_R(x) )
res
*/
> Rcpp::sourceCpp("~/git/stackoverflow/72383007/answer.cpp")
> set.seed(123)
> x <- max(0, rnorm(1, 50, 25))
> res <- microbenchmark::microbenchmark(R = gamma(x), Cpp = gammaStd(x), Sugar = gamma_R(x) )
>
res
Unit: nanoseconds
expr min lq mean median uq max neval cld
R 102 112.0 136.95 124 134.5 1068 100 a
Cpp 1111 1155.5 11930.02 1186 1260.0 1054813 100 a
Sugar 1142 1201.0 6355.92 1246 1301.5 506628 100 a
>