In C gibt es eine verzweigte Technik, um die absolute Differenz zwischen zwei vorzeichenlosen Ints zu berechnen? Zum Beispiel möchte ich für die Variablen a und b den Wert 2 für Fälle, wenn a = 3, b = 5 oder b = 3, a = 5. Idealerweise möchte ich auch die Berechnung mithilfe der SSE-Register vektorisieren können.
Es gibt mehrere Möglichkeiten dies zu tun, ich erwähne nur eins:
SSE4
PMINUD
und PMAXUD
, um den größeren Wert in Register # 1 und den kleineren Wert in Register # 2 zu trennen. MMX / SSE2
PCMPGTD
und (a-b)
(b-a)
, um den korrekten Wert für die absolute Differenz auszuwählen. Von tommesani.com besteht eine Lösung für dieses Problem darin, die vorzeichenlose Subtraktion mit Sättigung zweimal zu verwenden.
Da die Sättigungssubtraktion nie unter 0 fällt, berechnen Sie: r1 = (a-b) .sättigen r2 = (b-a) .saturierend
Wenn a größer als b ist, enthält r1 die Antwort und r2 wird 0 und umgekehrt für b & gt; a. Eine ODER-Verknüpfung der beiden Teilergebnisse ergibt das gewünschte Ergebnis.
Laut das VTUNE Benutzerhandbuch , PSUBUSB / PSUBUSW ist für 128-Bit-Register verfügbar, so dass Sie eine Menge Parallelisierung auf diese Weise erhalten können.
berechnet die Differenz und gibt den absoluten Wert zurück
%Vor%Dies erfordert eine Operation weniger, die die vorzeichenbehaftete Vergleichsoperation verwendet, und erzeugt weniger Registerdruck.
Gleicher Registerdruck wie zuvor, zwei weitere Ops, bessere Verzweigung und Zusammenführung von Abhängigkeitsketten, Befehlspaarung für die Dekodierung von uops und separate Einheitenauslastung. Obwohl dies eine Last erfordert, die nicht im Cache sein kann. Ich habe keine Ideen nach diesem.
%Vor%Nach dem Timing jeder Version mit 2 Millionen Iterationen auf einem Core2Duo sind die Unterschiede nicht messbar. Wähle also, was leichter zu verstehen ist.
SSE2:
Scheint ungefähr so schnell zu sein wie Phernosts zweite Funktion. Manchmal plant GCC es einen vollen Zyklus schneller, andere mal ein wenig langsamer.
%Vor%SSSE3:
Immer etwas schneller als vorher. Abhängig davon, wie Dinge außerhalb der Schleife deklariert werden, gibt es viele Variationen. (Wenn Sie beispielsweise " a
" und " b
volatile
" erstellen, wird die Verarbeitung beschleunigt. Dies scheint jedoch ein zufälliger Effekt für die Planung zu sein.) Dies ist jedoch konsistent am schnellsten um einen Zyklus oder so.
SSE4 (thx rwong):
Kann das nicht testen.
%Vor%Probieren Sie das aus (nimmt zweite Ergänzungen an, was OK ist, wenn Sie nach SSE fragen):
%Vor%Erläuterung: Das Zeichen-Bit (Bit 31) wird bis zum ersten Bit übertragen. das | 1 Teil stellt sicher, dass der Multiplikator entweder 1 oder -1 ist. Multiplikationen sind auf modernen CPUs schnell.
Einer oder mehrere der folgenden Punkte führen wahrscheinlich zu verzweigungsfreiem Code, abhängig von der Maschine und dem Compiler, da die bedingten Ausdrücke alle sehr einfach sind.
Ich habe nicht alle Antworten durchgelesen, aber möglicherweise sind einige der folgenden im Vektorcode dargestellt; Sicherlich sind alle unten genannten vektorisierbar (wenn Sie den unsignierten Vergleich haben, um damit zu beginnen, oder fälschen Sie ihn, indem Sie zuerst die msb umschalten.). Ich dachte, es wäre hilfreich, praktische skalare Antworten auf die Frage zu haben.
%Vor%Dies funktioniert auf x86_64 (oder irgendetwas, wo 64-Bit-Temps im Prinzip frei sind)
%Vor%