Ich weiß, dass Valarrays syntaktischen Zucker haben
Ich muss sagen, dass ich nicht std::valarrays
viel syntaktischen Zucker habe. Die Syntax ist anders, aber ich würde den Unterschied nicht "Zucker" nennen. Die API ist komisch. Der Abschnitt über std::valarray
s in der Programmiersprache C ++ erwähnt diese ungewöhnliche API und die Tatsache, dass, da std::valarray
erwartet wird , dass s stark optimiert ist, alle Fehlermeldungen, die Sie während der Verwendung erhalten, wahrscheinlich nicht intuitiv sind.
Aus Neugier habe ich mich std::valarray
vor ungefähr einem Jahr dagegen gestellt std::vector
. Ich habe nicht mehr den Code oder die genauen Ergebnisse (obwohl es nicht schwer sein sollte, einen eigenen zu schreiben). Mit GCC habe ich zwar einen kleinen Leistungsvorteil bei der Verwendung std::valarray
für einfache Mathematik erzielt, aber nicht für meine Implementierungen zur Berechnung der Standardabweichung (und natürlich ist die Standardabweichung nicht so komplex, was die Mathematik betrifft). Ich vermute, dass Operationen an jedem Element in einem großen std::vector
Spiel besser mit Caches spielen als Operationen an std::valarray
s. ( HINWEIS : Nach den Ratschlägen von musiphil habe ich es geschafft, von vector
und eine nahezu identische Leistung zu erzielen valarray
.)
Am Ende entschied ich mich für die Verwendung, std::vector
während ich mich intensiv mit Dingen wie Speicherzuweisung und temporärer Objekterstellung befasste.
Beide std::vector
und std::valarray
speichern die Daten in einem zusammenhängenden Block. Sie greifen jedoch mit unterschiedlichen Mustern auf diese Daten zu, und was noch wichtiger ist, die API für std::valarray
fördert andere Zugriffsmuster als die API für std::vector
.
Für das Beispiel der Standardabweichung musste ich in einem bestimmten Schritt den Mittelwert der Sammlung und die Differenz zwischen dem Wert jedes Elements und dem Mittelwert ermitteln.
Für die habe std::valarray
ich so etwas gemacht wie:
std::valarray<double> original_values = ... // obviously I put something here
double mean = original_values.sum() / original_values.size();
std::valarray<double> temp(mean, original_values.size());
std::valarray<double> differences_from_mean = original_values - temp;
Ich war vielleicht schlauer mit std::slice
oder std::gslice
. Es ist jetzt über fünf Jahre her.
Denn std::vector
ich habe etwas in der Art getan:
std::vector<double> original_values = ... // obviously, I put something here
double mean = std::accumulate(original_values.begin(), original_values.end(), 0.0) / original_values.size();
std::vector<double> differences_from_mean;
differences_from_mean.reserve(original_values.size());
std::transform(original_values.begin(), original_values.end(), std::back_inserter(differences_from_mean), std::bind1st(std::minus<double>(), mean));
Heute würde ich das sicherlich anders schreiben. Wenn nichts anderes, würde ich C ++ 11 Lambdas nutzen.
Es ist offensichtlich, dass diese beiden Codeausschnitte unterschiedliche Funktionen haben. Zum einen erstellt das std::vector
Beispiel keine Zwischensammlung wie das std::valarray
Beispiel. Ich denke jedoch, dass es fair ist, sie zu vergleichen, da die Unterschiede mit den Unterschieden zwischen std::vector
und zusammenhängen std::valarray
.
Als ich diese Antwort schrieb, vermutete ich, dass das Subtrahieren des Werts von Elementen von zwei std::valarray
s (letzte Zeile im std::valarray
Beispiel) weniger cachefreundlich wäre als die entsprechende Zeile im std::vector
Beispiel (die zufällig auch die letzte Zeile ist).
Es stellt sich jedoch heraus, dass
std::valarray<double> original_values = ... // obviously I put something here
double mean = original_values.sum() / original_values.size();
std::valarray<double> differences_from_mean = original_values - mean;
Funktioniert genauso wie im std::vector
Beispiel und hat eine nahezu identische Leistung. Am Ende stellt sich die Frage, welche API Sie bevorzugen.