Ich finde die Antwort darauf nirgends,
Wie speichere ich ein Array auf den maximalen Wert des Array-Typs?
Ich hätte gedacht, dass memset(ZBUFFER,0xFFFF,size)
funktionieren würde, wo ZBUFFER ein 16-Bit Integer-Array ist. Stattdessen bekomme ich -1s durch.
Die Idee ist auch, dass das so schnell wie möglich funktioniert (es ist ein zbuffer, der jeden Frame initialisieren muss). Wenn es einen besseren Weg gibt (und immer noch so schnell oder schneller), lass es mich wissen.
>bearbeiten: Zur Klarstellung brauche ich ein int-Array mit Vorzeichen.
In C ++ würden Sie std :: fill und std :: numeric_limits verwenden.
%Vor%Dies funktioniert mit jedem Typ.
In C sollten Sie memset
, das den Wert von Bytes festlegt, nicht beibehalten. Um ein Array anderer Typen als char
(ev.% Co_de%) zu initialisieren, müssen Sie auf eine manuelle unsigned
-Schleife zurückgreifen.
-1 und 0xFFFF sind das Gleiche in einer 16-Bit-Ganzzahl unter Verwendung einer Zweierkomplementdarstellung. Sie erhalten nur -1, weil Sie entweder Ihr Array als short
anstatt als unsigned short
deklariert haben. Oder weil Sie die Werte bei der Ausgabe in signed umwandeln.
Übrigens ist Ihre Annahme falsch, dass Sie außer bytes mit memset etwas einstellen können. memset(ZBUFFER, 0xFF, size)
hätte das Gleiche gemacht.
In C ++ können Sie ein Array mit einem Wert mit dem Algorithmus std::fill
füllen.
Dies ist weder schneller noch langsamer als Ihr aktueller Ansatz. Es hat jedoch den Vorteil, zu arbeiten.
Geschwindigkeit nicht der Sprache zuordnen. Das ist für Implementierungen von C. Es gibt C-Compiler, die schnellen, optimalen Maschinencode und C-Compiler erzeugen, die langsamen, nicht optimalen Maschinencode erzeugen. Genauso für C ++. Eine "schnelle, optimale" Implementierung könnte Code optimieren, der langsam erscheint . Daher macht es keinen Sinn, eine Lösung schneller zu nennen als eine andere. Ich werde über die Korrektheit sprechen und dann über Leistung sprechen, egal wie unbedeutend es ist. Es wäre eine bessere Idee, Ihren Code zu profilieren, um sicherzugehen, dass dies tatsächlich der Flaschenhals ist, aber machen wir weiter.
Betrachten wir zuerst die sinnvollste Option: Eine Schleife, die int
-Werte kopiert. Durch das Lesen des Codes wird klar, dass die Schleife SHRT_MAX
korrekt jedem int
-Element zuweist. Sie können unten einen Testfall dieser Schleife sehen, der versucht, das größtmögliche Array zu verwenden, das zu der Zeit von malloc
zugewiesen werden kann.
Ich habe dies auf meinem System ausgeführt, das mit verschiedenen aktivierten Optimierungen kompiliert wurde ( -O3 -march=core2 -funroll-loops
). Hier ist die Ausgabe:
Beachten Sie die "Ausführungszeit" ... Das ist ziemlich schnell! Wenn überhaupt, ist der Flaschenhals hier die Cache-Lokalität eines so großen Arrays, weshalb ein guter Programmierer versuchen wird, Systeme zu entwerfen, die nicht so viel Speicher verbrauchen ... Nun, dann betrachten wir die Option memset. Hier ist ein Zitat aus dem Memset-Handbuch :
Die Funktion memset () kopiert c (umgewandelt in ein unsigned char ) in jedes der ersten n Bytes des Objekts, auf das s zeigt.
Daher konvertiert es 0xFFFF in ein unsigniertes Zeichen (und kürzt möglicherweise diesen Wert) und weist dann den konvertierten Wert den ersten size
Bytes zu. Dies führt zu einem falschen Verhalten. Ich mag es nicht, sich darauf zu verlassen, dass der Wert SHRT_MAX als eine Folge von Bytes dargestellt wird, die den Wert (unsigned char) 0xFFFF
speichern, da dies auf Übereinstimmung beruht. Mit anderen Worten, das Hauptproblem ist hier, dass memset für Ihre Aufgabe nicht geeignet ist. Benutze es nicht. Nachdem dies gesagt wurde, ist hier ein Test, abgeleitet von dem obigen Test, der verwendet wird, um die Geschwindigkeit von memset zu testen:
Eine triviale byte-kopierende memset-Schleife iteriert sizeof (int)
mal mehr als die Schleife in meinem ersten Beispiel. Wenn man bedenkt, dass meine Implementierung ein ziemlich optimales memset verwendet, ist hier die Ausgabe:
Diese Tests werden wahrscheinlich sehr unterschiedlich ausfallen. Ich habe sie nur einmal ausgeführt, um eine ungefähre Vorstellung zu bekommen. Hoffentlich sind Sie zu der gleichen Schlussfolgerung gekommen, die ich habe: Häufige Compiler sind ziemlich gut darin, einfache Schleifen zu optimieren, und es ist nicht wert, hier über Mikrooptimierungen nachzutragen.
Zusammenfassend:
Dies liegt an Zweierkomplement . Sie müssen Ihren Array-Typ in unsigned short
ändern, um den maximalen Wert zu erhalten, oder 0x7FFF
verwenden.
Beachten Sie, dass dies die letzten paar Bytes, if (SIZE % sizeof(short))
In C kannst du es wie Adrian Panasiuk machen, und du kannst auch die Kopierschleife ausrollen. Das Abrollen bedeutet, dass größere Stücke gleichzeitig kopiert werden. Das äußerste Ende des Loop-Abrollvorgangs kopiert den gesamten Frame mit einem Null-Frame wie folgt:
%Vor%tatsächliches Löschen:
%Vor%(Sie können mit verschiedenen Größen des leeren ZBUFFER experimentieren, ab vier Bytes und dann eine Schleife um das Memcpy herum.)
Wie immer testen Sie Ihre Ergebnisse, wenn a) es sich lohnt, diesen Teil des Programms zu optimieren und b) welchen Unterschied die verschiedenen Initialisierungstechniken machen. Es hängt von vielen Faktoren ab. Für die letzten paar Prozent der Leistung müssen Sie möglicherweise auf Assembler-Code zurückgreifen.
Wenn Sie "memset" sagen, müssen Sie diese Funktion tatsächlich verwenden? Das ist nur eine byteweise Zuweisung, so dass es nicht mit vorzeichenbehafteten Arrays funktioniert.
Wenn Sie jeden Wert auf den Maximalwert setzen möchten, verwenden Sie beispielsweise:
std::fill( ZBUFFER, ZBUFFER+len, std::numeric_limits<short>::max() )
wenn len
die Anzahl der Elemente ist (nicht die Größe in Bytes Ihres Arrays)