2017-10-11 2 views
2

Je suis nouveau à Rcpp et explore ses applications. En particulier, je suis en train d'accélérer la fonction suivante, en partie construite sur un previous answer:Rcpp - accélérer les tirages normaux aléatoires dans et pendant la boucle

code = 'NumericVector RcppFun(int N){ 
      NumericVector out(N); 
      for (int i = 0; i < N; ++i) { 
       double V = 0; 
       while(V > -1e04 && V < 1e04) { 
        V += R::rnorm(10, 100); 
        } 
       out[i] = V; 
       } 
      return out; 
      }' 
cppFunction(code) 
system.time(RcppFun(1e05)) 

Le code est nettement plus rapide que son homologue de R, mais nécessite encore quelques secondes pour courir sur mon ordinateur. Étant donné que j'ai besoin d'appeler cette fonction plusieurs fois, je me demandais si je pouvais encore améliorer ses performances. Je pensais que modifier la déclaration logique dans la boucle while ou changer la fonction RNG rendrait la fonction plus rapide, mais je ne pouvais pas comprendre comment.

Merci pour votre suggestion!

EDIT: juste pour être complet, voici le code que j'ai écrit en C++ basé sur la suggestion très utile de Dirk:

#include <Rcpp.h> 
// [[Rcpp::depends(RcppZiggurat)]] 
#include <Ziggurat.h> 
using namespace Rcpp; 
static Ziggurat::Ziggurat::Ziggurat zigg; 
// [[Rcpp::export]] 
NumericVector ZiggFun(int N){ 
      NumericVector out(N); 
      for (int i = 0; i < N; ++i) { 
       double V = 0; 
       while(V > -1e04 && V < 1e04) { 
        V += 10 + zigg.norm()*100; 
        } 
       out[i] = V; 
       } 
      return out; 
      } 

Sur la base des estimations rbenchmark :: référence, le nouveau code est maintenant plus de 7 fois plus vite!

Répondre

3

Vous pouvez utiliser RcppZiggurat pour accélérer RNG tirages - Je synchronisation des comparaisons dans le paquet:

R> library(RcppZiggurat) 
R> library(microbenchmark) 
R> microbenchmark(rnorm(1e5), zrnorm(1e5)) 
Unit: microseconds 
      expr  min  lq mean median  uq  max neval cld 
    rnorm(1e+05) 6148.781 6169.917 6537.31 6190.073 6923.357 10166.96 100 b 
zrnorm(1e+05) 719.458 887.554 1016.03 901.182 939.652 2880.47 100 a 
R> 

Ce RNG peut être utilisé dans d'autres paquets au niveau C++ aussi. C'est juste un en-tête que vous tirez de la manière habituelle.