Come il titolo della domanda dice, mi piacerebbe sapere perché il byte di codice compilato R (usando compiler::cmpfun
) è più veloce di codice Rcpp equivalente per la seguente funzione matematica:Perché questo codice Rcpp è più lento del byte R compilato?
func1 <- function(alpha, tau, rho, phi) {
abs((alpha + 1)^(tau) * phi - rho * (1- (1 + alpha)^(tau))/(1 - (1 + alpha)))
}
Dal momento che si tratta di una semplice operazione numerica , Mi sarei aspettato che Rcpp (funcCpp
e funcCpp2
) fosse molto più veloce del byte R compilato (func1c
e func2c
), specialmente dal momento che R avrebbe avuto un sovraccarico maggiore per l'archiviazione di (1+alpha)**tau
o avrebbe dovuto ricalcolarlo. In effetti, il calcolo di questo esponente due volte sembra più rapido dell'allocazione di memoria in R(), che sembra particolarmente controintuitivo, dal momento che lo n
è di grandi dimensioni. La mia altra ipotesi è che forse lo compiler::cmpfun
stia facendo un po 'di magia, ma mi piacerebbe sapere se è davvero così.
Quindi, in realtà, le due cose che mi piacerebbe sapere è:
Perché funcCpp e funcCpp2 più lento di func1c e func2c? (Rcpp più lento delle funzioni R compilate)
Perché funcCpp è più lento di func2? (Codice Rcpp più lento di pura R)
FWIW, ecco la mia C++ e la versione R dati
user% g++ --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.0 (clang-700.0.72)
Target: x86_64-apple-darwin14.3.0
Thread model: posix
user% R --version
R version 3.2.2 (2015-08-14) -- "Fire Safety"
Copyright (C) 2015 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin14.5.0 (64-bit)
Ed ecco la R e Rcpp codice:
library(Rcpp)
library(rbenchmark)
func1 <- function(alpha, tau, rho, phi) {
abs((1 + alpha)^(tau) * phi - rho * (1- (1 + alpha)^(tau))/(1 - (1 + alpha)))
}
func2 <- function(alpha, tau, rho, phi) {
pval <- (alpha + 1)^(tau)
abs(pval * phi - rho * (1- pval)/(1 - (1 + alpha)))
}
func1c <- compiler::cmpfun(func1)
func2c <- compiler::cmpfun(func2)
func3c <- Rcpp::cppFunction('
double funcCpp(double alpha, int tau, double rho, double phi) {
double pow_val = std::exp(tau * std::log(alpha + 1.0));
double pAg = rho/alpha;
return std::abs(pow_val * (phi - pAg) + pAg);
}')
func4c <- Rcpp::cppFunction('
double funcCpp2(double alpha, int tau, double rho, double phi) {
double pow_val = pow(alpha + 1.0, tau) ;
double pAg = rho/alpha;
return std::abs(pow_val * (phi - pAg) + pAg);
}')
res <- benchmark(
func1(0.01, 200, 100, 1000000),
func1c(0.01, 200, 100, 1000000),
func2(0.01, 200, 100, 1000000),
func2c(0.01, 200, 100, 1000000),
func3c(0.01, 200, 100, 1000000),
func4c(0.01, 200, 100, 1000000),
funcCpp(0.01, 200, 100, 1000000),
funcCpp2(0.01, 200, 100, 1000000),
replications = 100000,
order='relative',
columns=c("test", "replications", "elapsed", "relative"))
Ed ecco l'output di rbenchmark
:
test replications elapsed relative
func1c(0.01, 200, 100, 1e+06) 100000 0.349 1.000
func2c(0.01, 200, 100, 1e+06) 100000 0.372 1.066
funcCpp2(0.01, 200, 100, 1e+06) 100000 0.483 1.384
func4c(0.01, 200, 100, 1e+06) 100000 0.509 1.458
func2(0.01, 200, 100, 1e+06) 100000 0.510 1.461
funcCpp(0.01, 200, 100, 1e+06) 100000 0.524 1.501
func3c(0.01, 200, 100, 1e+06) 100000 0.546 1.564
func1(0.01, 200, 100, 1e+06) 100000 0.549 1.573K
Questo 'func1c' è più veloce di' func2c' è probabilmente dovuto al garbage collector o ad altre cause difficili da determinare. Esegui più volte la chiamata "benchmark" e vedrai queste due funzioni cambiare posizione nella classifica. Cercare di misurare qualcosa che richiede solo 1 microsecondo per essere eseguito è molto difficile. –
@bunk "È davvero sorprendente che le funzioni C siano più veloci del C++?" - Sì, assolutamente. Non c'è motivo di aspettarselo. In effetti, il codice C++ può essere spesso reso * più veloce * rispetto al codice C dello stesso livello di astrazione e non dovrebbe mai essere più lento. Ecco ulteriori informazioni: http: //programmers.stackexchange.it/a/29136/2366 –
@bunk Vero, sono dodici contro una dozzina. Non ci dovrebbero essere differenze in alcun modo. La "magia" che Rcpp gira potrebbe ovviamente incorrere in un sovraccarico - tuttavia, anche 'UN'/'PROTECT' viene chiamato qui? La mia conoscenza dell'API di R's C è alquanto imprecisa ma, poiché questi sono tutti argomenti, non dovrebbe esserci alcuna protezione necessaria, dovrebbe esserci? –