Frage

Ich mag Vektoren viel. Sie sind nette und schnell. Aber ich weiß, dieses Ding namens ein valarray existiert. Warum sollte ich einen valarray anstelle eines Vektors verwenden? Ich weiß valarrays haben einige syntaktischen Zucker, aber anders als das, wann sind sie nützlich?

War es hilfreich?

Lösung

Valarrays (value-Arrays) dazu bestimmt ist, einige der Geschwindigkeit von Fortran zu C ++ zu bringen. Sie würden keinen valarray von Zeigern machen, damit der Compiler Annahmen über den Code machen und es besser optimieren. (Der Hauptgrund, dass Fortran so schnell ist, ist, dass es kein Zeigertyp ist so kann es kein Zeiger Aliasing sein.)

Valarrays haben auch Klassen, die Sie erlauben, sie in einem recht einfachen Weg zu zerschneiden, obwohl dieser Teil des Standard ein bisschen mehr Arbeit nutzen könnte. Ändern der Größe von ihnen ist destruktiv und es fehlt ihnen an Iteratoren.

Also, wenn es die Zahlen, die Sie arbeiten mit und Komfort ist nicht so wichtig Verwendung valarrays. Andernfalls Vektoren sind nur viel bequemer.

Andere Tipps

valarray ist eine Art Waise, die am falschen Ort zur falschen Zeit geboren wurden. Es ist ein Versuch der Optimierung, ziemlich speziell für die Maschinen, die für schwere Mathe verwendet wurden, als es geschrieben wurde -. Insbesondere Vektor-Prozessoren wie der Crays

Für einen Vektorprozessor, was Sie wollten im Allgemeinen tun, war eine einzige Operation auf eine ganze Reihe gilt, dann gilt die nächste Operation auf das gesamte Array, und so weiter, bis Sie alles getan, was würden Sie tun mußten.

Wenn Sie mit ziemlich kleiner Arrays zu tun hat, aber, dass tendenziell mit Caching schlecht arbeiten. Auf modernsten Maschinen, was Sie in der Regel bevorzugen würden (soweit möglich) wäre Teil des Arrays zu laden, gehen Sie alle Operationen darauf du gehst, dann auf den nächsten Teil des Feldes zu bewegen.

valarray ist auch jede Möglichkeit von Aliasing beseitigen soll, die (zumindest theoretisch) Geschwindigkeit der Compiler verbessern läßt, weil es kostenlos ist zum Speichern von Werten in Registern. In Wirklichkeit bin ich aber gar nicht sicher, dass eine wirkliche Umsetzung Vorteil dieser in einem signifikanten Ausmaß annimmt. Ich vermute, es ist eher eine Huhn-Ei-Art von Problem - ohne Compiler-Unterstützung es nicht populär ist worden, und solange es nicht populär ist, niemand die Mühe machen würde auf ihrem Compiler arbeitet, sie zu unterstützen <. / p>

Es gibt auch einen verwirrende (buchstäblich) Array von Hilfsklassen mit valarray zu verwenden. Sie erhalten slice, slice_array, gslice und gslice_array mit Stücken eines valarray zu spielen, und es wie ein mehrdimensionales Array handeln machen. Sie könnten auch mask_array auf „Maske“, eine Operation (zum Beispiel Hinzufügen von Elementen in x zu y, sondern nur an den Stellen, an denen z nicht Null ist) erhalten. Um mehr als trivial Verwendung von valarray zu machen, haben Sie viel über diese Nebenklassen zu lernen, von denen einige ziemlich komplex und von denen keines scheint (zumindest für mich) sehr gut dokumentiert.

Fazit:., Während es Momente der Brillanz hat, und kann einige Dinge tun, recht ordentlich, es gibt auch einige sehr gute Gründe, dass es (und bleibt an Sicherheit grenzender Wahrscheinlichkeit) unklar

Edit (acht Jahre später, im Jahr 2017): Einige der vorhergehenden hat zumindest in gewissem Grad obsolet geworden. Für ein Beispiel, hat Intel eine optimierte Version von valarray für ihre Compiler implementiert. Es nutzt die Intel Integrated Performance Primitives (Intel IPP) Leistung zu verbessern. Obwohl die Verbesserung zweifellos genaue Leistung variiert, zeigt ein kurzer Test mit einfachen Code um eine 2:. 1 Verbesserung der Geschwindigkeit, im Vergleich zu identischem Code mit der „Standard“ Implementierung von valarray zusammengestellt

Also, während ich nicht ganz überzeugt bin, dass C ++ Programmierer valarray in großer Zahl zu verwenden beginnen, gibt es mindestens einige Umstände, unter denen es eine Verbesserung der Geschwindigkeit zur Verfügung stellen kann.

Während der Standardisierung von C ++ 98, wurde valarray entwickelt eine Art schnelle mathematische Berechnungen zu ermöglichen. Doch um diese Zeit Todd Veldhuizen erfunden Ausdrucksvorlagen und erstellt blitz ++ und ähnliche Template-meta-Techniken wurden erfunden , die valarrays ziemlich veraltet, bevor der Standard überhaupt veröffentlicht wurde gemacht. IIRC, der ursprüngliche Antragsteller (n) von valarray aufgegeben Hälfte in die Standardisierung, die (wenn true) hat es auch nicht helfen.

ISTR, dass der Hauptgrund, es nicht von der Norm entfernt ist, dass niemand die Zeit genommen hat, das Problem gründlich und schreibt einen Vorschlag zu bewerten, um sie zu entfernen.

Bitte bedenken Sie jedoch, dass all diese vage Hörensagen erinnert. Nehmen Sie diese mit einem Körnchen Salz und hoffen, dass jemand korrigiert oder bestätigt dies.

  

Ich weiß valarrays hat einigen syntaktischen Zucker

Ich muss sagen, dass ich nicht glaube, viel std::valarrays haben in Art und Weise der syntaktischen Zucker. Die Syntax ist anders, aber ich würde den Unterschied nicht nennen „Zucker“. Die API ist seltsam. Der Abschnitt über std::valarrays in The C ++ Programming Language erwähnt diese ungewöhnliche API und die Tatsache, dass, da std::valarrays erwartet hoch optimiert werden, alle Fehlermeldungen, die Sie erhalten, während mit ihnen werden wahrscheinlich nicht intuitiv sein.

Aus Neugier, vor etwa einem Jahr ausgespielt ich std::valarray gegen std::vector. Ich habe nicht mehr den Code oder die genauen Ergebnisse (obwohl es nicht schwer sein, sollten Sie Ihre eigenen zu schreiben). Mit GCC I haben ein wenig Performance-Vorteil erhalten, wenn std::valarray für einfache mathematische verwenden, aber nicht für meine Ausführungen Standardabweichung zu berechnen (und, natürlich, ist die Standardabweichung nicht so komplex, so weit wie Mathematik geht). Ich vermute, dass Operationen auf jedes Element in einem großen std::vector besser spielen mit Caches als Operationen auf std::valarrays ( Hinweis , folgende Ratschläge von musiphil , ich habe es geschafft, fast identische Leistung von vector und valarray zu bekommen).

Am Ende entschied ich mich std::vector zu verwenden, während Aufmerksamkeit auf Dinge wie Speicherzuweisung und temporäre Objekterstellung zu zahlen.


Sowohl std::vector und std::valarray speichert die Daten in einem zusammenhängenden Block. Aber sie Zugriff auf die Daten verschiedene Muster verwendet wird, und was noch wichtiger ist, die API für std::valarray fördert unterschiedliche Zugriffsmuster als die API für std::vector.

Für die Standardabweichung beispielsweise in einem bestimmten Schritt brauchte ich die Sammlung des mittleren und die Differenz zwischen jedem Element den Wert und den Mittelwert zu finden.

Für die std::valarray, ich habe so etwas 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 habe mit std::slice oder std::gslice klüger gewesen. Es ist schon mehr als fünf Jahre.

Für std::vector, ich habe etwas entlang der Linien von:

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 Code-Schnipsel, verschiedene Dinge tun. Zum einen ist das std::vector Beispiel keine Zwischen Sammlung machen wie das std::valarray Beispiel der Fall ist. Aber ich denke, es ist fair, sie zu vergleichen, da die Unterschiede zu den Unterschieden zwischen std::vector und std::valarray gebunden sind.

Wenn ich diese Antwort schrieb, ich vermuten, dass der Wert von Elementen aus zwei std::valarrays (letzter Zeile im std::valarray Beispiel) Subtrahieren wäre weniger Cache freundlicher als die entsprechende Zeile in dem std::vector Beispiel (was auch passiert sein, die letzten Linie).

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;

Ist das gleiche wie das std::vector Beispiel, und hat fast identische Leistung. Am Ende ist die Frage, welche API Sie es vorziehen.

valarray sollte einige Fortran Vektor-Verarbeitung Güte abfärben auf C ++ lassen. Irgendwie ist die notwendige Compiler-Unterstützung nie wirklich passiert ist.

Die Josuttis Bücher enthält einige interessante (etwas abschätzig) Kommentar zu valarray ( hier und hier ).

Allerdings Intel scheinen jetzt in ihren jüngsten Compiler Versionen erneuten Besuch valarray werden (siehe zB Schieber 9 ); Dies ist eine interessante Entwicklung, da ihr 4-Wege-SIMD-SSE-Befehlssatz über ist es viel besser, wahrscheinlich würde mit einer Abstraktion zu codieren, um 8-Wege-AVX und 16-Wegen Larrabee Anweisungen und im Interesse der Portabilität verbunden werden wie valarray als (sagen wir) intrinsics.

fand ich eine gute Verwendung für valarray. Es ist zu verwenden valarray wie numpy Arrays.

auto x = linspace(0, 2 * 3.14, 100);
plot(x, sin(x) + sin(3.f * x) / 3.f + sin(5.f * x) / 5.f);

 image description hier

Wir implementieren oben mit valarray.

valarray<float> linspace(float start, float stop, int size)
{
    valarray<float> v(size);
    for(int i=0; i<size; i++) v[i] = start + i * (stop-start)/size;
    return v;
}

std::valarray<float> arange(float start, float step, float stop)
{
    int size = (stop - start) / step;
    valarray<float> v(size);
    for(int i=0; i<size; i++) v[i] = start + step * i;
    return v;
}

string psstm(string command)
{//return system call output as string
    string s;
    char tmp[1000];
    FILE* f = popen(command.c_str(), "r");
    while(fgets(tmp, sizeof(tmp), f)) s += tmp;
    pclose(f);
    return s;
}

string plot(const valarray<float>& x, const valarray<float>& y)
{
    int sz = x.size();
    assert(sz == y.size());
    int bytes = sz * sizeof(float) * 2;
    const char* name = "plot1";
    int shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
    ftruncate(shm_fd, bytes);
    float* ptr = (float*)mmap(0, bytes, PROT_WRITE, MAP_SHARED, shm_fd, 0);
    for(int i=0; i<sz; i++) {
        *ptr++ = x[i];
        *ptr++ = y[i];
    }

    string command = "python plot.py ";
    string s = psstm(command + to_string(sz));
    shm_unlink(name);
    return s;
}

Außerdem müssen wir Python-Skript.

import sys, posix_ipc, os, struct
import matplotlib.pyplot as plt

sz = int(sys.argv[1])
f = posix_ipc.SharedMemory("plot1")
x = [0] * sz
y = [0] * sz
for i in range(sz):
    x[i], y[i] = struct.unpack('ff', os.read(f.fd, 8))
os.close(f.fd)
plt.plot(x, y)
plt.show()

Der C ++ 11-Standard sagt:

  

Die valarray Array-Klassen frei von bestimmten Formen sein, definiert von   Aliasing, so dass Operationen auf diesen Klassen optimiert werden.

Siehe C ++ 11 26.6.1-2.

std :: valarray ist für schwere numerische Aufgaben bestimmt sind, wie Computational Fluid Dynamics oder Dynamics Computational Struktur, in der Sie Arrays mit Millionen, manchmal zig Millionen von Artikeln, und Sie durchlaufen sie in einer Schleife mit auch Millionen von Zeitschritten. Vielleicht hat heute std :: vector eine vergleichbare Leistung, aber vor etwa 15 Jahren valarray war fast obligatorisch, wenn Sie einen effizienten numerischen Solver schreiben wollte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top