Wie findet man am schnellsten heraus, ob eine Zahl gerade oder ungerade ist?
Wie findet man am schnellsten heraus, ob eine Zahl gerade oder ungerade ist?
fragt
Das ist ziemlich bekannt
static inline int is_odd_A(int x) { return x & 1; }
ist effizienter als
static inline int is_odd_B(int x) { return x % 2; }
Aber wenn der Optimierer eingeschaltet ist, wird is_odd_B
nicht anders sein als is_odd_A
? Nein – mit gcc-4.2 -O2
erhalten wir (in der ARM-Assembly):
_is_odd_A:
and r0, r0, #1
bx lr
_is_odd_B:
mov r3, r0, lsr #31
add r0, r0, r3
and r0, r0, #1
rsb r0, r3, r0
bx lr
Wir sehen das is_odd_B
dauert 3 Anweisungen mehr als is_odd_A
der Hauptgrund ist, weil
((-1) % 2) == -1
((-1) & 1) == 1
Jedochgenerieren alle folgenden Versionen denselben Code wie is_odd_A
:
#include <stdbool.h>
static inline bool is_odd_D(int x) { return x % 2; } // note the bool
static inline int is_odd_E(int x) { return x % 2 != 0; } // note the !=
Was bedeutet das? Der Optimierer ist normalerweise so ausgeklügelt, dass er für diese einfachen Dinge Der klarste Code reicht aus, um die beste Effizienz zu gewährleisten.
-
noch besser, spezifizieren Sie das Argument als
unsigned
.– Kartoffelklatsche
9. Februar 2010 um 18:59 Uhr
-
@Kartoffelwatter:
x%2U
oderx&1U
. 🙂– R.. GitHub HÖR AUF, EIS ZU HELFEN
21. September 2010 um 3:15 Uhr
-
was ist, wenn Sie 1 eingeben, es sagt ungerade
– ichimaru
5. September 2018 um 1:33 Uhr
-
x & 1
wird falsche Antworten auf seine Komplementsysteme geben. Für vollständig portierbaren Code, der auf den normalen Zweierkomplementsystemen, die uns wichtig sind, effizient kompiliert werden kann, müssen Sie entweder unsigned or verwendenx % 2 != 0
– Peter Cordes
12. Dezember 2018 um 4:51 Uhr
AndiDog
Übliche Vorgehensweise:
int number = ...;
if(number % 2) { odd }
else { even }
Alternative:
int number = ...;
if(number & 1) { odd }
else { even }
Getestet auf GCC 3.3.1 und 4.3.2, beide haben ungefähr die gleiche Geschwindigkeit (ohne Compiler-Optimierung), da beide im Ergebnis resultieren and
Anweisung (auf x86 kompiliert) – Ich weiß, dass die Verwendung der div
Anweisungen für Modulo wären viel langsamer, daher habe ich es überhaupt nicht getestet.
-
Der Compiler hat den Test wahrscheinlich vollständig entfernt, da beide wahrscheinlich konstant sind. Erinnere dich daran
gcc
ohne Optionen ist gleichbedeutend mitgcc -O2
Dies ist eine nicht triviale Ebene der Geschwindigkeitsoptimierung. Überprüfen Sie die generierte Assembly, um sicherzugehen.– dmckee — Ex-Moderator-Kätzchen
9. Februar 2010 um 13:46 Uhr
-
Ist bitweises XOR nicht schneller als bitweises AND? Ist es nicht mit XOR-Operation möglich?
– bitte
9. Februar 2010 um 14:00 Uhr
-
@dmckee: Ich weiß nicht, warum Sie denken, dass Level 2 die Standardeinstellung war. Die Manpage sagt eindeutig “-O0 Nicht optimieren. Dies ist die Standardeinstellung.”. Aber ich habe den Assembler-Code trotzdem überprüft und er wurde nicht aus dem Code entfernt (deshalb dauert es 7 Sekunden, bis jeder Test ausgeführt wird).
– AndiDog
9. Februar 2010 um 14:14 Uhr
-
@aks: Ich habe bitweises XOR getestet und es ist mit der gleichen Geschwindigkeit wie AND/Modulo (Übrigens erzeugen diese beiden denselben Code auf x86, nämlich eine “and” -Anweisung). Wie auch immer, könnten Sie mir sagen, wie ich ungerade/gerade mit bestimmen kann nur eine XOR-Anweisung?
– AndiDog
9. Februar 2010 um 14:16 Uhr
-
InRe-Optimierungsstufen: Mea Cupla.
– dmckee — Ex-Moderator-Kätzchen
9. Februar 2010 um 14:41 Uhr
wenn (x & 1) wahr ist, dann ist es ungerade, andernfalls ist es gerade.
-
Dies schlägt auf einer Maschine fehl, die das eigene Komplement verwendet.
– Jason
9. Februar 2010 um 14:25 Uhr
-
Außerdem, und dies ist ein allgemeiner Kommentar zu allen bisherigen Antworten, wurde in der Frage nicht angegeben, dass die Zahl eine ganze Zahl war. Sie können keine bitweisen Operationen mit Gleitkommazahlen durchführen (zumindest nicht ohne Typumwandlungs-Hacker).
– Schizz
9. Februar 2010 um 14:49 Uhr
-
@Skizz: Definiere gerade oder ungerade für eine Nicht-Ganzzahl.
– dmckee — Ex-Moderator-Kätzchen
9. Februar 2010 um 15:10 Uhr
-
@dmckee: float i=2.0f; // gerade Zahl! aber i&1 funktioniert nicht.
– Schizz
9. Februar 2010 um 19:55 Uhr
-
@Skizz Sie können es für 2.0 definieren Weil es hat einen ganzzahligen Ausdruck. Das Richtige ist also, in int zu konvertieren und das Ergebnis wie besprochen zu behandeln.
– dmckee — Ex-Moderator-Kätzchen
9. Februar 2010 um 20:24 Uhr
bool is_odd = number & 1;
int i=5;
if ( i%2 == 0 )
{
// Even
} else {
// Odd
}
-
Das Prüfen des niederwertigsten Bits wäre schneller als der Modulo-Operator. Ich wette jedoch, dass die meisten Compiler “mod 2” in “and 1” umwandeln würden
– Bramp
9. Februar 2010 um 13:00 Uhr
-
@bramp: sie können nicht wenn
i
ist unterschrieben.– R.. GitHub HÖR AUF, EIS ZU HELFEN
21. September 2010 um 3:17 Uhr
-
@R: Bist du sicher? Beispielsweise ist das Zweierkomplement von 127 “01111111” und -127 ist “10000001”, beide haben das niedrigstwertige Bit gesetzt.
– Bramp
21. September 2010 um 11:25 Uhr
Maurits Rijk
int is_odd(int n)
{
if (n == 0)
return 0;
else if (n == 1)
return 1;
else
return !is_odd(n - 1);
}
Oh warte, hast du gesagt am schnellsten übrigens nicht am lustigsten. Mein Fehler 😉
Die obige Funktion funktioniert natürlich nur für positive Zahlen.
-
Das Prüfen des niederwertigsten Bits wäre schneller als der Modulo-Operator. Ich wette jedoch, dass die meisten Compiler “mod 2” in “and 1” umwandeln würden
– Bramp
9. Februar 2010 um 13:00 Uhr
-
@bramp: sie können nicht wenn
i
ist unterschrieben.– R.. GitHub HÖR AUF, EIS ZU HELFEN
21. September 2010 um 3:17 Uhr
-
@R: Bist du sicher? Beispielsweise ist das Zweierkomplement von 127 “01111111” und -127 ist “10000001”, beide haben das niedrigstwertige Bit gesetzt.
– Bramp
21. September 2010 um 11:25 Uhr
Überprüfen Sie, ob das letzte Bit 1 ist.
int is_odd(int num) {
return num & 1;
}
-
Siehe den Kommentar von Tom, gleiches gilt hier. Dies wird nicht in C kompiliert.
– AndiDog
9. Februar 2010 um 14:22 Uhr
-
Richtig … geändert in int. (FWIW, einige Build-Umgebungen #define oder typedef bool to int).
– 0xfe
9. Februar 2010 um 14:54 Uhr
Das ist eine gute Anfänger-C-Frage. +1 von mir.
– t0mm13b
9. Februar 2010 um 13:21 Uhr
Ist bitweises XOR nicht schneller als bitweises UND? Ist es nicht mit XOR-Operation möglich?
– bitte
9. Februar 2010 um 14:00 Uhr
@aks: Wenn Sie einen Compiler mit vollem Funktionsumfang verwenden, kennt dieses Backend diese Tricks mit ziemlicher Sicherheit besser als du. Schreiben Sie für Klarheit und Lesbarkeit und überlassen Sie die Bit-Fummelei, die Zyklusoptimierung dem Profi. Wirklich. Und wenn Sie mit den Ergebnissen nicht zufrieden sind, erstellen Sie ein Profil und untersuchen Sie die Hotspots im Detail.
– dmckee — Ex-Moderator-Kätzchen
9. Februar 2010 um 14:05 Uhr
@dmckee: Wie auch immer, ich würde gerne eine Lösung sehen, die nur eine einzige XOR-Anweisung verwendet. Ich glaube nicht, dass das möglich ist…
– AndiDog
9. Februar 2010 um 14:59 Uhr
Stellen Sie sicher, dass Sie dies vor der Mikrooptimierung gelesen haben: linux-kongress.org/2009/slides/…
– mmx
9. Februar 2010 um 15:16 Uhr