Gibt es eine schnellere Möglichkeit als x >= start && x <= end
in C oder C ++ zu testen, ob eine Ganzzahl zwischen zwei Ganzzahlen liegt?
UPDATE : Meine spezifische Plattform ist iOS. Dies ist Teil einer Box-Unschärfe-Funktion, die Pixel auf einen Kreis in einem bestimmten Quadrat beschränkt.
UPDATE : Nachdem ich die akzeptierte Antwort ausprobiert hatte , erhielt ich in der einen Codezeile eine Beschleunigung um eine Größenordnung, weil ich es auf normale x >= start && x <= end
Weise gemacht hatte.
UPDATE : Hier ist der After- und Before-Code mit Assembler von XCode:
NEUER WEG
// diff = (end - start) + 1
#define POINT_IN_RANGE_AND_INCREMENT(p, range) ((p++ - range.start) < range.diff)
Ltmp1313:
ldr r0, [sp, #176] @ 4-byte Reload
ldr r1, [sp, #164] @ 4-byte Reload
ldr r0, [r0]
ldr r1, [r1]
sub.w r0, r9, r0
cmp r0, r1
blo LBB44_30
ALTER WEG
#define POINT_IN_RANGE_AND_INCREMENT(p, range) (p <= range.end && p++ >= range.start)
Ltmp1301:
ldr r1, [sp, #172] @ 4-byte Reload
ldr r1, [r1]
cmp r0, r1
bls LBB44_32
mov r6, r0
b LBB44_33
LBB44_32:
ldr r1, [sp, #188] @ 4-byte Reload
adds r6, r0, #1
Ltmp1302:
ldr r1, [r1]
cmp r0, r1
bhs LBB44_36
Es ist ziemlich erstaunlich, wie das Reduzieren oder Eliminieren von Verzweigungen eine solch dramatische Beschleunigung bewirken kann.
c++
c
performance
math
jjxtra
quelle
quelle
Antworten:
Es gibt einen alten Trick, dies mit nur einem Vergleich / Zweig zu tun. Ob es die Geschwindigkeit wirklich verbessert, ist möglicherweise fraglich, und selbst wenn dies der Fall ist, ist es wahrscheinlich zu wenig, um es zu bemerken oder sich darum zu kümmern, aber wenn Sie nur mit zwei Vergleichen beginnen, sind die Chancen für eine enorme Verbesserung ziemlich gering. Der Code sieht aus wie:
Bei einem typischen, modernen Computer (dh bei allem, was ein Zweierkomplement verwendet) ist die Konvertierung in vorzeichenloses nicht wirklich - nur eine Änderung in der Art und Weise, wie dieselben Bits angezeigt werden.
Beachten Sie, dass Sie in einem typischen Fall
upper-lower
außerhalb einer (vermuteten) Schleife vorberechnen können , sodass normalerweise keine nennenswerte Zeit zur Verfügung steht. Dies verbessert nicht nur die Anzahl der Verzweigungsbefehle, sondern verbessert auch (im Allgemeinen) die Verzweigungsvorhersage. In diesem Fall wird derselbe Zweig verwendet, unabhängig davon, ob die Zahl unter dem unteren Ende oder über dem oberen Ende des Bereichs liegt.Wie dies funktioniert, ist die Grundidee ziemlich einfach: Eine negative Zahl ist, wenn sie als vorzeichenlose Zahl betrachtet wird, größer als alles, was als positive Zahl begann.
In der Praxis übersetzt diese Methode
number
das Intervall zum Ursprungspunkt und prüft, obnumber
es sich in dem Intervall befindet[0, D]
, in demD = upper - lower
. Wennnumber
unterhalb der Untergrenze: negativ , und wenn oberhalb der Obergrenze: größer alsD
.quelle
lower <= x & x <= upper
(stattlower <= x && x <= upper
) auch zu einer besseren Leistung führen?Es ist selten möglich, signifikante Optimierungen für Code in so kleinem Maßstab vorzunehmen. Große Leistungssteigerungen ergeben sich aus der Beobachtung und Änderung des Codes von einer höheren Ebene aus. Möglicherweise können Sie die Notwendigkeit des Bereichstests ganz beseitigen oder nur O (n) anstelle von O (n ^ 2) ausführen. Möglicherweise können Sie die Tests neu anordnen, sodass immer eine Seite der Ungleichung impliziert ist. Selbst wenn der Algorithmus ideal ist, ist es wahrscheinlicher, dass Gewinne erzielt werden, wenn Sie sehen, wie dieser Code den Bereichstest 10 Millionen Mal durchführt, und Sie einen Weg finden, sie zu stapeln und SSE zu verwenden, um viele Tests parallel durchzuführen.
quelle
Dies hängt davon ab, wie oft Sie den Test für dieselben Daten durchführen möchten.
Wenn Sie den Test einmal durchführen, gibt es wahrscheinlich keine sinnvolle Möglichkeit, den Algorithmus zu beschleunigen.
Wenn Sie dies für einen sehr endlichen Satz von Werten tun, können Sie eine Nachschlagetabelle erstellen. Das Durchführen der Indizierung ist möglicherweise teurer. Wenn Sie jedoch die gesamte Tabelle in den Cache einfügen können, können Sie alle Verzweigungen aus dem Code entfernen, was die Arbeit beschleunigen sollte.
Für Ihre Daten wäre die Nachschlagetabelle 128 ^ 3 = 2.097.152. Wenn Sie eine der drei Variablen steuern können, berücksichtigen Sie alle Fälle, in denen
start = N
gleichzeitig , sinkt die Größe des Arbeitssatzes auf128^2 = 16432
Bytes, was in die meisten modernen Caches gut passen sollte.Sie müssten immer noch den tatsächlichen Code vergleichen, um festzustellen, ob eine verzweigungslose Nachschlagetabelle ausreichend schneller ist als die offensichtlichen Vergleiche.
quelle
bool between[start][end][x]
. Wenn Sie wissen, wie Ihr Zugriffsmuster aussehen wird (z. B. x nimmt monoton zu), können Sie die Tabelle so gestalten, dass die Lokalität erhalten bleibt, auch wenn die gesamte Tabelle nicht in den Speicher passt.Diese Antwort soll über einen Test berichten, der mit der akzeptierten Antwort durchgeführt wurde. Ich habe einen Closed-Range-Test mit einem großen Vektor sortierter zufälliger Ganzzahlen durchgeführt und zu meiner Überraschung ist die grundlegende Methode von (niedrig <= num && num <= hoch) tatsächlich schneller als die oben akzeptierte Antwort! Der Test wurde mit HP Pavilion g6 (AMD A6-3400APU mit 6 GB RAM) durchgeführt. Hier ist der Kerncode, der zum Testen verwendet wird:
verglichen mit der folgenden, die oben akzeptierte Antwort ist:
Achten Sie darauf, dass randVec ein sortierter Vektor ist. Für jede Größe von MaxNum schlägt die erste Methode die zweite auf meinem Computer!
quelle
Für jede Überprüfung des variablen Bereichs:
Die Bitoperation ist schneller:
Dadurch werden zwei Zweige zu einem.
Wenn Sie sich für typsicher interessieren:
Sie können mehrere variable Bereichsprüfungen miteinander kombinieren:
Dadurch werden 4 Zweige zu 1.
Es ist 3,4-mal schneller als das alte in gcc:
quelle
Ist es nicht möglich, nur eine bitweise Operation für die Ganzzahl durchzuführen?
Da es zwischen 0 und 128 liegen muss, ist es, wenn das 8. Bit gesetzt ist (2 ^ 7), 128 oder mehr. Der Randfall wird jedoch ein Schmerz sein, da Sie einen umfassenden Vergleich wünschen.
quelle
x <= end
, woend <= 128
. Nichtx <= 128
.