21 Stimmen

Würden Sie num%2 oder num&1 verwenden, um zu prüfen, ob eine Zahl gerade ist?

Nun, es gibt mindestens zwei einfache Möglichkeiten, um festzustellen, ob eine bestimmte Zahl gerade ist oder nicht:

 1. if (num%2 == 0) { /* even */ } 
 2. if ((num&1) == 0) { /* even */ }

Ich halte die zweite Option für weitaus eleganter und sinnvoller und verwende sie daher in der Regel. Aber es ist nicht nur eine Frage des Geschmacks; die tatsächliche Leistung kann variieren: Normalerweise sind die bitweisen Operationen (wie die logial-and hier) viel effizienter als eine mod (oder div) Operation. Natürlich kann man argumentieren, dass einige Compiler dies ohnehin optimieren können, und ich stimme dem zu... aber einige werden es nicht tun.

Ein weiterer Punkt ist, dass der zweite Punkt für weniger erfahrene Programmierer etwas schwieriger zu verstehen sein könnte. Darauf würde ich antworten, dass es wahrscheinlich nur für alle von Vorteil ist, wenn diese Programmierer sich die kurze Zeit nehmen, um diese Art von Anweisungen zu verstehen.

Was meinen Sie dazu?

Die beiden angegebenen Ausschnitte sind nur korrekt, wenn num ist entweder ein vorzeichenloser int oder eine negative Zahl mit Zweierkomplement-Darstellung. - Wie einige Kommentare richtig feststellen.

7voto

Bill Forster Punkte 6017

Es hängt alles vom Kontext ab. Ich selbst bevorzuge den &1-Ansatz, wenn es sich um einen Systemkontext auf niedriger Ebene handelt. In vielen dieser Arten von Kontexten bedeutet "ist gerade" für mich eher, dass es ein niedriges Bit Null hat, als dass es durch zwei teilbar ist.

JEDOCH: Ihr Einzeiler hat einen Fehler.

Sie müssen gehen

if( (x&1) == 0 )

no

if( x&1 == 0 )

Letztere verknüpft x mit 1==0, d.h. sie verknüpft x mit 0, was 0 ergibt, was natürlich immer als falsch gewertet wird.

Wenn Sie es also genau so gemacht haben, wie Sie vorschlagen, sind alle Zahlen ungerade!

3voto

Peter Alexander Punkte 51742

Jeder moderne Compiler wird die Modulo-Operation wegoptimieren, so dass die Geschwindigkeit keine Rolle spielt.

Ich würde sagen, dass die Verwendung von Modulo die Dinge leichter verständlich machen würde, aber das Erstellen einer is_even Funktion, die die x & 1 Methode bietet Ihnen das Beste aus beiden Welten.

3voto

Jon Seigel Punkte 11987

Sie sind beide ziemlich intuitiv.

Ich würde einen leichten Vorsprung geben an num % 2 == 0 aber ich habe wirklich keine Vorliebe. Sicherlich, was die Leistung angeht, ist es wahrscheinlich eine Mikro-Optimierung, also würde ich mir keine Sorgen machen.

2voto

Cody Gray Punkte 229889

Ich verbrachte Jahre darauf bestehen, dass jeder vernünftige Compiler, der den Platz, den er auf der Festplatte verbraucht, wert ist, optimieren würde num % 2 == 0 zu num & 1 == 0 . Als ich dann die Demontage aus einem anderen Grund analysierte, hatte ich die Gelegenheit, meine Vermutung zu überprüfen.

Es stellte sich heraus, dass ich mich geirrt hatte. Microsoft Visual Studio bis hin zur Version 2013 erzeugt den folgenden Objektcode für num % 2 == 0 :

    and ecx, -2147483647        ; the parameter was passed in ECX
    jns SHORT $IsEven
    dec ecx
    or  ecx, -2
    inc ecx
$IsEven:
    neg ecx
    sbb ecx, ecx
    lea eax, DWORD PTR [ecx+1]

Ja, in der Tat. Dies ist der Release-Modus, in dem alle Optimierungen aktiviert sind. Sie erhalten praktisch gleichwertige Ergebnisse, egal ob Sie für x86 oder x64 bauen. Sie werden mir wahrscheinlich nicht glauben; ich habe es selbst kaum geglaubt.

Es tut im Wesentlichen das, was Sie erwarten würden für num & 1 == 0 :

not  eax                        ; the parameter was passed in EAX
and  eax, 1

Im Vergleich dazu, GCC (bis hin zu v4.4) und Clang (bis hin zu v3.2) tun das, was man erwarten würde, und erzeugen identischen Objektcode für beide Varianten. Allerdings ist laut Matt Godbolts interaktiver Compiler , ICC 13.0.1 widerspricht auch meinen Erwartungen.

Sicher, diese Compiler sind nicht falsch . Es ist kein Fehler. Es gibt viele technische Gründe (wie in den anderen Antworten hinreichend dargelegt), warum diese beiden Codeschnipsel nicht identisch sind. Und es gibt sicherlich ein Argument, das lautet: "Vorzeitige Optimierung ist schlecht". Zugegeben, es gibt einen Grund, warum ich Jahre gebraucht habe, um dies zu bemerken, und selbst dann bin ich nur aus Versehen darüber gestolpert.

Aber, wie Doug T. sagte ist es wahrscheinlich am besten, eine IsEven Funktion in Ihrer Bibliothek, die all diese kleinen Details korrekt ausführt, damit Sie nie wieder darüber nachdenken müssen und Ihr Code lesbar bleibt. Wenn Sie regelmäßig mit MSVC arbeiten, werden Sie diese Funktion vielleicht so definieren, wie ich es getan habe:

bool IsEven(int value)
{
    const bool result = (num & 1) == 0;
    assert(result == ((num % 2) == 0));
    return result;   
}

0voto

Thomas Bonini Punkte 42356

Beide Ansätze sind nicht offensichtlich, insbesondere für jemanden, der neu in der Programmierung ist. Sie sollten eine inline Funktion mit einem beschreibenden Namen. Der Ansatz, den Sie darin verwenden, spielt keine Rolle (Mikrooptimierungen werden Ihr Programm höchstwahrscheinlich nicht merklich schneller machen).

Wie auch immer, ich glaube, dass 2) viel schneller ist, da es keine Division erfordert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X