Ich mag Vektoren sehr. Sie sind geschickt und schnell. Aber ich weiß, dass dieses Ding namens Valarray existiert. Warum sollte ich einen Valarray anstelle eines Vektors verwenden? Ich weiß, Valarrays haben syntaktischen Zucker, aber abgesehen davon, wann sind sie nützlich?
159
valarray
hier und hierAntworten:
Valarrays (Wert-Arrays) sollen einen Teil der Geschwindigkeit von Fortran in C ++ bringen. Sie würden kein Valarray von Zeigern erstellen, damit der Compiler Annahmen über den Code treffen und ihn besser optimieren kann. (Der Hauptgrund dafür, dass Fortran so schnell ist, ist, dass es keinen Zeigertyp gibt, sodass es kein Zeiger-Aliasing geben kann.)
Valarrays haben auch Klassen, mit denen Sie sie auf relativ einfache Weise aufteilen können, obwohl dieser Teil des Standards etwas mehr Arbeit erfordern könnte. Die Größenänderung ist destruktiv und es fehlen Iteratoren.
Wenn es sich also um Zahlen handelt, mit denen Sie arbeiten, und Bequemlichkeit nicht so wichtig ist, verwenden Sie Valarrays. Ansonsten sind Vektoren viel bequemer.
quelle
valarray
ist eine Art Waisenkind, das zur falschen Zeit am falschen Ort geboren wurde. Es ist ein Optimierungsversuch, ziemlich speziell für die Maschinen, die beim Schreiben für Hochleistungsmathematik verwendet wurden - speziell für Vektorprozessoren wie die Crays.Bei einem Vektorprozessor wollten Sie im Allgemeinen eine einzelne Operation auf ein gesamtes Array anwenden und dann die nächste Operation auf das gesamte Array anwenden usw., bis Sie alles getan haben, was Sie tun mussten.
Wenn Sie jedoch nicht mit relativ kleinen Arrays arbeiten, funktioniert dies beim Caching in der Regel schlecht. Auf den meisten modernen Computern würden Sie es im Allgemeinen (soweit möglich) vorziehen, einen Teil des Arrays zu laden, alle Operationen auszuführen, die Sie ausführen möchten, und dann mit dem nächsten Teil des Arrays fortzufahren.
valarray
soll auch jede Möglichkeit von Aliasing ausschließen, wodurch der Compiler (zumindest theoretisch) die Geschwindigkeit verbessern kann, da es freier ist, Werte in Registern zu speichern. In Wirklichkeit bin ich mir jedoch keineswegs sicher, ob eine echte Implementierung dies in nennenswertem Maße ausnutzt. Ich vermute, es ist eher ein Henne-Ei-Problem - ohne Compiler-Unterstützung wurde es nicht populär, und solange es nicht populär ist, wird sich niemand die Mühe machen, an seinem Compiler zu arbeiten, um es zu unterstützen.Es gibt auch eine verwirrende (buchstäblich) Reihe von Nebenklassen, die mit Valarray verwendet werden können. Sie erhalten
slice
,slice_array
,gslice
undgslice_array
mit Stücken von a zu spielenvalarray
, und es wie ein mehrdimensionales Array handeln machen. Sie können auchmask_array
eine Operation "maskieren" (z. B. Elemente in x zu y hinzufügen, jedoch nur an den Positionen, an denen z ungleich Null ist). Um mehr als nur trivial davon Gebrauch zu machenvalarray
, muss man viel über diese Nebenklassen lernen, von denen einige ziemlich komplex sind und von denen (zumindest für mich) keine sehr gut dokumentiert erscheint.Fazit: Während es Momente der Brillanz hat und einige Dinge ziemlich ordentlich erledigen kann, gibt es auch einige sehr gute Gründe, warum es dunkel ist (und mit ziemlicher Sicherheit bleiben wird).
Bearbeiten (acht Jahre später, im Jahr 2017): Einige der vorhergehenden sind zumindest teilweise veraltet. Zum Beispiel hat Intel eine optimierte Version von Valarray für seinen Compiler implementiert. Es verwendet die Intel Integrated Performance Primitives (Intel IPP), um die Leistung zu verbessern. Obwohl die genaue Leistungsverbesserung zweifellos unterschiedlich ist, zeigt ein schneller Test mit einfachem Code eine Verbesserung der Geschwindigkeit um 2: 1 im Vergleich zu identischem Code, der mit der "Standard" -Implementierung von kompiliert wurde
valarray
.Obwohl ich nicht ganz davon überzeugt bin, dass C ++ - Programmierer
valarray
in großer Zahl eingesetzt werden, gibt es zumindest einige Umstände, unter denen dies zu einer Geschwindigkeitsverbesserung führen kann.quelle
Während der Standardisierung von C ++ 98 wurde Valarray entwickelt, um schnelle mathematische Berechnungen zu ermöglichen. Zu dieser Zeit erfand Todd Veldhuizen jedoch Ausdrucksvorlagen und erstellte Blitz ++ , und ähnliche Template-Meta-Techniken wurden erfunden, die Valarrays ziemlich veraltet machten, bevor der Standard überhaupt veröffentlicht wurde. IIRC, die ursprünglichen Antragsteller von Valarray, gaben es auf halbem Weg in die Standardisierung auf, was (falls zutreffend) auch nicht half.
ISTR, dass der Hauptgrund dafür, dass es nicht aus dem Standard entfernt wurde, darin besteht, dass sich niemand die Zeit genommen hat, das Problem gründlich zu bewerten und einen Vorschlag zu schreiben, um es zu entfernen.
Bitte denken Sie jedoch daran, dass all dies vage an Hörensagen erinnert wird. Nehmen Sie dies mit einem Körnchen Salz und hoffen Sie, dass jemand dies korrigiert oder bestätigt.
quelle
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 überstd::valarray
s in der Programmiersprache C ++ erwähnt diese ungewöhnliche API und die Tatsache, dass, dastd::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 gestelltstd::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 Verwendungstd::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( HINWEIS : Nach den Ratschlägen von musiphil habe ich es geschafft, vonstd::vector
Spiel besser mit Caches spielen als Operationen anstd::valarray
s.vector
und eine nahezu identische Leistung zu erzielenvalarray
.)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
undstd::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ürstd::valarray
fördert andere Zugriffsmuster als die API fürstd::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:Ich war vielleicht schlauer mit
std::slice
oderstd::gslice
. Es ist jetzt über fünf Jahre her.Denn
std::vector
ich habe etwas in der Art getan: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 dasstd::valarray
Beispiel. Ich denke jedoch, dass es fair ist, sie zu vergleichen, da die Unterschiede mit den Unterschieden zwischenstd::vector
und zusammenhängenstd::valarray
.Als ich diese Antwort schrieb, vermutete ich, dass das Subtrahieren des Werts von Elementen von zwei
std::valarray
s (letzte Zeile imstd::valarray
Beispiel) weniger cachefreundlich wäre als die entsprechende Zeile imstd::vector
Beispiel (die zufällig auch die letzte Zeile ist).Es stellt sich jedoch heraus, dass
Funktioniert genauso wie im
std::vector
Beispiel und hat eine nahezu identische Leistung. Am Ende stellt sich die Frage, welche API Sie bevorzugen.quelle
std::vector
besser mit Caches spielen würde als astd::valarray
; Beide weisen ihren Elementen einen einzigen zusammenhängenden Speicherblock zu.valarray
obigen Beispiel mussten Sie keintemp
valarray
Objektstd::valarray<double> differences_from_mean = original_values - mean;
erstellen , aber Sie hätten es einfach tun können , und dann sollte das Cache-Verhalten dem desvector
Beispiels ähnlich sein . (Übrigens, wennmean
es wirklichint
nicht istdouble
, brauchen Sie es vielleichtstatic_cast<double>(mean)
.)valarray
. Ich muss sehen, ob das die Leistung verbessert. Was dasmean
Sein betrifftint
: Das war ein Fehler. Ich habe das Beispiel ursprünglich mitint
s geschrieben und dann festgestellt, dass dasmean
dann aufgrund von Kürzungen sehr weit vom tatsächlichen Mittelwert entfernt ist. Bei meiner ersten Bearbeitungsrunde habe ich jedoch einige notwendige Änderungen verpasst.valarray sollte einige FORTRAN-Vektorverarbeitungsgüte auf C ++ abfärben lassen. Irgendwie ist die notwendige Compiler-Unterstützung nie wirklich passiert.
Die Josuttis-Bücher enthalten einige interessante (etwas abfällige) Kommentare zu Valarray ( hier und hier ).
Intel scheint Valarray jedoch in seinen jüngsten Compiler-Versionen erneut zu besuchen (siehe z. B. Folie 9 ). Dies ist eine interessante Entwicklung, da der 4-Wege-SIMD-SSE-Befehlssatz bald durch 8-Wege-AVX- und 16-Wege-Larrabee-Befehle ergänzt wird. Im Interesse der Portabilität ist es wahrscheinlich viel besser, mit einer Abstraktion wie zu codieren Valarray als (sagen wir) intrinsics.
quelle
Ich habe eine gute Verwendung für Valarray gefunden. Es ist Valarray genau wie Numpy Arrays zu verwenden.
Wir können oben mit Valarray implementieren.
Außerdem benötigen wir ein Python-Skript.
quelle
Der C ++ 11 Standard sagt:
Siehe C ++ 11 26.6.1-2.
quelle
Mit können
std::valarray
Sie die mathematische Standardnotation wiev1 = a*v2 + v3
im Auslieferungszustand verwenden. Dies ist mit Vektoren nur möglich, wenn Sie Ihre eigenen Operatoren definieren.quelle
std :: valarray ist für schwere numerische Aufgaben wie Computational Fluid Dynamics oder Computational Structure Dynamics vorgesehen, bei denen Sie Arrays mit Millionen, manchmal mehreren zehn Millionen Elementen haben und diese in einer Schleife mit ebenfalls Millionen von Zeitschritten durchlaufen. Vielleicht hat std :: vector heute eine vergleichbare Leistung, aber vor etwa 15 Jahren war valarray fast obligatorisch, wenn Sie einen effizienten numerischen Löser schreiben wollten.
quelle