Ich weiß, dass Valarrays syntaktischen Zucker haben
Ich muss sagen, dass ich nicht std::valarraysviel syntaktischen Zucker habe. Die Syntax ist anders, aber ich würde den Unterschied nicht "Zucker" nennen. Die API ist komisch. Der Abschnitt über std::valarrays in der Programmiersprache C ++ erwähnt diese ungewöhnliche API und die Tatsache, dass, da std::valarrayerwartet 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::valarrayvor 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::valarrayfü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::vectorSpiel besser mit Caches spielen als Operationen an std::valarrays. ( HINWEIS : Nach den Ratschlägen von musiphil habe ich es geschafft, von vectorund eine nahezu identische Leistung zu erzielen valarray.)
Am Ende entschied ich mich für die Verwendung, std::vectorwährend ich mich intensiv mit Dingen wie Speicherzuweisung und temporärer Objekterstellung befasste.
Beide std::vectorund std::valarrayspeichern 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::valarrayfö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::valarrayich 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::sliceoder std::gslice. Es ist jetzt über fünf Jahre her.
Denn std::vectorich 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::vectorBeispiel keine Zwischensammlung wie das std::valarrayBeispiel. Ich denke jedoch, dass es fair ist, sie zu vergleichen, da die Unterschiede mit den Unterschieden zwischen std::vectorund zusammenhängen std::valarray.
Als ich diese Antwort schrieb, vermutete ich, dass das Subtrahieren des Werts von Elementen von zwei std::valarrays (letzte Zeile im std::valarrayBeispiel) weniger cachefreundlich wäre als die entsprechende Zeile im std::vectorBeispiel (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::vectorBeispiel und hat eine nahezu identische Leistung. Am Ende stellt sich die Frage, welche API Sie bevorzugen.