Ich möchte Rcpp::NumericMatrix
als Argumenttyp für eine C++ - Funktion verwenden, die es durchlaufen wird. Soll ich jetzt den gesamten Inhalt des Rcpp::NumericMatrix
in ein C-artiges Array kopieren, um eine gute Performance zu haben oder ist es auch schnell den [] -Operator von Rcpp::NumericMatrix
in einer C++ - Schleife mehrfach zu benutzen? Gibt es einen schnelleren Weg als den Direktzugriff, um eine Rcpp::NumericMatrix
Instanz zu durchlaufen?Ist es eine gute Idee, Schleifen für Rcpps NumericMatrix in C++ zu verwenden?
Antwort
Da es ein ziemlich entspannter Tag ist und ich nicht in der Lage war, schnell einen Maßstab dafür zu finden (Rcpp Sugar Abschnitt 4 ist TBD und Abschnitt 6 ist TBD) ... Und meine allgemeine Neugier ... Lass es uns geben ein gehen!
Erstens, für den Zugriff auf eine NumericMatrix
‚s c-Stil Array wir zuerst eine NumericMatrix
zu std::vector
konvertieren. Aus der std::vector
können wir ein c-style-Array, das von einem Zeiger gesteuert wird, extrahieren. Unter dieser Struktur erstellen wir eine Kopie der Daten vollständig. Nichtsdestoweniger können wir die vorgeschlagene Frage untersuchen und dann einige.
Im Folgenden finden Sie eine kurze Test-Suite von Funktionen, die auf vier verschiedene Komponenten konzentrieren:
- c-style Array
std::accumulate
- Looping einen
std::vector
- Element weist Zugang mit
NumericMatrix
Nun habe ich in der reinen c-style Funktion "betrogen", da ich nicht versucht habe, die Größe des Arrays von selbst über sizeof()
Berechnungen zu berechnen. (Dies hätte potentiell einige Probleme verursacht, da die Zeigergröße gegeben worden wäre ...)
Lassen Sie uns die Testsuite der Funktionen überprüfen.
#include <Rcpp.h>
// [[Rcpp::export]]
double c_for_access(const Rcpp::NumericMatrix& x){
// Cast to std vector
std::vector<double> v = Rcpp::as<std::vector<double> >(x);
// Convert to c-style pointer
double* pv = &v[0];
// Sum using a pointer
double sum = 0;
for(unsigned int i = 0; i < v.size(); i++){
sum += *(pv+i);
}
return sum;
}
// [[Rcpp::export]]
double stl_for_access(const Rcpp::NumericMatrix& x){
// Cast to std vector
std::vector<double> v = Rcpp::as<std::vector<double> >(x);
// Summing Operation
double sum = 0;
for(unsigned int i = 0; i < v.size(); i++){
sum += v[i];
}
return sum;
}
// [[Rcpp::export]]
double stl_access(const Rcpp::NumericMatrix& x){
// Cast to STL Vector
std::vector<double> v = Rcpp::as<std::vector<double> >(x);
// Use STL to return sum
return std::accumulate(v.begin(), v.end(), 0.0); // Important to specify 0.0 instead of 0.
}
// [[Rcpp::export]]
double matrix_access(const Rcpp::NumericMatrix& x) {
// Define matrix information and looping variables.
unsigned int r = x.nrow(), c = x.ncol(), i, j;
// Sum elements
double sum = 0;
for(i = 0; i < r; i++){
for(j = 0; j < c; j++){
sum += x(i,j);
}
}
return sum;
}
Nun lassen Sie uns einige Daten erzeugen:
# Set seed for reproducibility
set.seed(1337)
# Create a 100x100 matrix
x = matrix(rnorm(10000),nrow=100,ncol=100)
Als nächstes berechnen wir und überprüfen Sie die Summe der einzelnen Objekte sicherzustellen, dass sie alle gleich sind:
# Calculate each object
oracle = sum(x) # Oracle is the correct answer given by R
c.out = c_for_access(x)
stl.loop = stl_for_access(x)
stl.lib = stl_access(x)
rcpp.pure = matrix_access(x)
# Check all equal
all.equal(oracle, c.out)
all.equal(oracle, stl.loop)
all.equal(oracle, stl.lib)
all.equal(oracle, rcpp.pure)
Schließlich haben wir Führen Sie für jede Funktion einen Microbenchmark aus:
# install.packages("microbenchmark")
microbenchmark::microbenchmark(oracle = sum(x),
c.out = c_for_access(x),
stl.loop = stl_for_access(x),
stl.lib = stl_access(x),
rcpp.pure = matrix_access(x)
)
Vom-Micro haben wir:
Unit: microseconds
expr min lq mean median uq max neval
oracle 8.105 8.705 9.11406 8.7060 9.0060 24.016 100
c.out 30.319 31.220 31.75767 31.2210 31.5210 54.636 100
stl.loop 30.320 30.921 32.56819 31.2210 31.5210 55.836 100
stl.lib 30.319 30.920 31.64063 31.2205 31.6705 50.133 100
rcpp.pure 9.907 10.807 10.95122 10.8070 11.1070 12.909 100
die Matrix Summierung über Rcpp
So ist ~ 2 Mikrosekunden langsamer als R, aber es ist wesentlich schneller als der std::vector
und c-Stil Array-Setup.
Q. E.D?
Super! Die Konvertierung ist also ein erheblicher Overhead, genau das, was ich wissen wollte. – phinz
- 1. Ist es eine gute Idee, statische Klasse AppContext zu verwenden?
- 2. Ist es eine gute Idee, BootFaces & PrimeFAces zusammen zu verwenden?
- 3. Ist es eine gute Idee, das Factory-Methodenentwurfsmuster zum Verwalten verschiedener Klassenversionen in C# zu verwenden?
- 4. Ist MSMQ eine gute Idee?
- 5. Ist es eine gute Idee, eine Python-Klasse zu hashen?
- 6. Ist eine gute Idee, Couchbase mit Rails zu verwenden?
- 7. Ist es eine gute Übung, size_t in C++ zu verwenden?
- 8. Ist es eine gute Idee, Zeichenfolgen für alle Datentypen in JSON zu verwenden?
- 9. Django: Ist es eine gute Idee, JS dynamisch zu generieren?
- 10. Ist es eine gute Idee, alte Schienen Migrationen zu reduzieren?
- 11. Ist es eine gute Idee, NSNumberFormatterBehavior10_4 über NSNumberFormatterBehaviorDefault zu bevorzugen?
- 12. Ist es eine gute Idee, Methoden zu Scala-Fallklassen hinzuzufügen
- 13. Ist es eine gute Idee, eine berechnete Spalte als Teil eines Primärschlüssels zu verwenden?
- 14. Ist es eine gute Idee, die Klasse als Namespace in Python zu verwenden
- 15. Ist es eine gute Idee, NSDecimalNumber für Fließkomma-Arithmetik anstatt einfach doppelt zu verwenden?
- 16. Es ist eine gute Idee, Ruby für Socket-Programmierung zu verwenden?
- 17. Verwenden Sie * dies eine gute Idee?
- 18. Ist es eine gute Idee, für jeden Client in SQL Server eine andere Datenbank zu erstellen?
- 19. Ist if (TRUE) eine gute Idee in C?
- 20. ist es eine gute Idee, Klassen mit demselben Namen in verschiedenen Namespaces in C# zu haben?
- 21. Globale Konstanten in separater Datei. Ist es eine gute Idee?
- 22. Was ist MongoDBs strikter Modus und ist es eine gute Idee zu verwenden?
- 23. Ist es eine gute Idee() auf viele kleine, wiederverwendbare reactjs Komponenten in redux zu verwenden, verbinden
- 24. Wann ist es keine gute Idee, durch Referenz zu gehen?
- 25. Ist es eine gute Idee, MySQL und Neo4j zusammen zu verwenden?
- 26. Ist es eine gute Idee, eine schwere Datenbank (Datenspeicher) Aktivität Website eine gute Idee mit gwt + appengine?
- 27. Ist es eine gute Idee, Database Mail als E-Mail-Relay-Server zu verwenden?
- 28. MongoDB ist es eine gute Idee _id als Entity ID zu verwenden
- 29. Ist es eine gute Idee, jquery Funktion zu verwenden, die jede 500ms laufen?
- 30. Ist eine DLL kompatibel zu allen Datenbanken eine gute Idee
Probieren Sie beides aus und vergleichen? –
Es ist alles in der Rcpp Dokumentation und Pakete diskutiert. Wir haben sogar Benchmarks. –
@DirkEddelbuettel Danke! Ich habe heute mit Rcpp angefangen. – phinz