Wann ist es angebracht, einen bitweisen Operator in einem bedingten Ausdruck zu verwenden?

15

Zunächst einige Hintergrundinformationen: Ich bin ein ausgebildeter IT-Lehrer und versuche, die Booleschen Operatoren von Java in meine Klasse der 10. Klasse einzuführen. Mein Lehrer-Mentor sah sich ein Arbeitsblatt an, das ich vorbereitet und kommentiert hatte, dass ich sie nur ein einziges & oder | verwenden lassen könnte die Operatoren zu bezeichnen, weil sie "dasselbe tun".

Mir ist der Unterschied zwischen & und && bewusst.
& ist ein bitweiser Operator, der für die Verwendung zwischen ganzen Zahlen vorgesehen ist, um "Bit-Twiddling" durchzuführen.
&& ist ein Bedingungsoperator, der für die Verwendung zwischen Booleschen Werten vorgesehen ist.

Um zu beweisen, dass diese Operatoren nicht immer "dasselbe tun", habe ich ein Beispiel gesucht, bei dem die Verwendung der bitweisen Werte zwischen Booleschen Werten zu einem Fehler führen würde. Ich habe dieses Beispiel gefunden

boolean bitwise;
boolean conditional;
int i=10, j=12;
bitwise = (i<j) | ((i=3) > 5); // value of i after oper: 3
System.out.println(bitwise+ " "+ i);
i=10; 
conditional = (i<j) || (i=3) > 5 ;  // value of i after oper: 10
System.out.println(conditional+ " "+ i);
i=10; 
bitwise = (i>j) & (i=3) > 5;   // value of i after oper: 3
System.out.println(bitwise+ " "+ i);
i=10; 
conditional = (i>j) && (i=3) > 5;  // value of i after oper: 10
System.out.println(conditional+ " "+ i);

Dieses Beispiel zeigt, dass, wenn ein Wert in der zweiten Hälfte des Ausdrucks geändert werden muss, dies zu einem Unterschied zwischen den Ergebnissen führen würde, da bitweise ein eifriger Operator ist, während sich die Bedingung wie ein Kurzschluss verhält (die zweite nicht auswertet) half, wenn die erste Hälfte im Fall von && falsch ist, und true im Fall von ||).

Ich habe ein Problem mit diesem Beispiel. Warum möchten Sie einen Wert gleichzeitig mit einem Vergleich ändern? Es scheint keine robuste Art des Codierens zu sein. Ich war immer abgeneigt, in meinem Produktionscode mehrere Operationen in einer einzigen Zeile auszuführen. Es scheint etwas zu sein, was ein "Coding Cowboy" ohne Gewissen in Bezug auf die Wartbarkeit seines Codes tun würde. Ich weiß, dass Code in einigen Domänen so kompakt wie möglich sein muss, aber dies ist sicherlich eine schlechte Praxis im Allgemeinen.

Ich kann meine Entscheidung, die Verwendung von && und || zu fördern, erläutern über & und | denn dies ist eine anerkannte Kodierungskonvention in der Softwareentwicklung .

Aber könnte mir jemand bitte ein besseres, sogar reales Beispiel für die Verwendung eines bitweisen Operators in einem bedingten Ausdruck geben?

Deerasha
quelle

Antworten:

16

Dies ist sinnvoll, wenn Sie einen Maskierungsvorgang ausführen

if ((a & b)> 0) {...}

wo a und b ganze Zahlen sind

|| und | und && und & sind nicht austauschbar

| und & werden meistens nie in einem bedingten Ausdruck für sich selbst erscheinen (der Punkt des von Ihnen eingeschlossenen Links ist, dass solche Dinge meistens Fehler sind)

EDIT: Streite nicht mit deinem Mentor; Selbst wenn Sie gewinnen, verlieren Sie. Erklären Sie stattdessen, dass Sie die Schüler nicht verwirren möchten, indem Sie logische und bitweise Operatoren in derselben Lektion mischen. Sie könnten erklären, dass, wenn i = 3 und j = 2, i & j = 2 ist, während i & j ein Fehler ist. Die einfachere Erklärung ist jedoch, dass Sie boolesche (logische) Operatoren unterrichten. Wenn Sie also bitweise Äquivalente in Sonderfällen einsetzen, lenkt dies vom Hauptpunkt der Lektion ab. Es besteht keine Notwendigkeit, den Mentor "falsch" zu machen und keine Gegenbeispiele vorzulegen. Der Schwerpunkt der Lektion liegt auf Booleschen Operatoren, nicht auf bitweisen Operatoren.

Wenn Sie anfangen, bitweise Operatoren zu lernen, müssen Sie nicht unbedingt die Sonderfälle anzeigen, in denen + und - die gleichen Ergebnisse wie & und | liefern

Steven A. Lowe
quelle
Der obige Code ist zwar nicht falsch, es kann verwirrend sein, aber wie es aussieht, enthält der Code keinen Fehler, oder? Ich bin damit einverstanden, dass die Verwendung von bitweisen Operatoren auf diese Weise nicht sehr lesbar ist. Ich würde es nicht mögen, wenn ich es in einer Codeüberprüfung sehen würde, aber es ist legal, Java (und C # ignoriert auch die Datei System.out.println).
Steve
Danke, dass du @Steven A. Lowe geantwortet hast. Sie sagte : „|| und | und && und & sind nicht austauschbar“ aber bitwise = !(true & true == false);und condition = !(true && true == false);wird sowohl auf true zu bewerten, so dass in diesem Fall , dass sie austauschbar sind? Syntaktisch vielleicht, da der Code noch kompiliert. Ich würde zustimmen, dass sie semantisch für verschiedene Dinge verwendet werden, wie ich in Absatz 2 erwähnt habe. Das sagst du! und & "erscheinen fast nie in einer Bedingung für sich". Ich suche nach diesen "fast nie" Fällen und frage mich, ob sie legitim existieren.
Deerasha
@Deerasha: || und && funktionieren nur auf Booleschen Werten. & und | Operationen mit Ganzzahlen und Booleschen Werten - Es hat wenig Sinn, bitweise Operatoren (die auf mehrere Bits angewendet werden sollen) zu verwenden, um Boolesche Werte zu manipulieren. Wenn Sie dies mit Abbruch tun, kann dies zu verwirrendem Code und unerwartetem Verhalten führen (dh, wenn Sie versehentlich eine Ganzzahl anstelle von a verwenden) Boolean, die bitweisen Operatoren werden sich nicht beschweren)
Steven A. Lowe
Ja, @Steve Haigh, der Compiler lehnt das nicht ab, aber es ist nicht der richtige Weg, sie zu verwenden, gemessen an dem veröffentlichten Codierungsstandard, mit dem ich verlinkt bin. Kann ich mich darauf verlassen, es zu schließen, weil es nicht mit einem Kodierungsstandard übereinstimmt, oder sollte Java vielleicht darauf hinweisen, dass dies eine missbräuchliche Verwendung ist?
Deerasha
2
@Steven A. Lowe: Wenn i = 3 und j = 2, dann ist i & j = 2, während i & j ein Fehler ist. Dies ist brillant! Es ist einfach und es macht den Punkt. Ab der 10. Klasse ist dies ebenfalls ein wahrscheinlicher Fehler, da sie sich immer noch an den Booleschen Typ gewöhnen und an das, worauf sich die Operatoren beziehen würden. Ich danke dir sehr! Toller Rat, auch nicht mit meinem Mentor zu streiten.
Deerasha
12

Die nicht-bitweisen Operatoren &&und ||sind Kurzschlussoperatoren. Mit anderen Worten, &&wenn die LHS falsch ist, wird die RHS niemals ausgewertet. mit ||wenn die LHS wahr ist, dann wird die RHS nie ausgewertet. Auf der anderen Seite sind die bitweisen Operatoren &und |nicht kurzgeschlossen und werten immer sowohl die LHS als auch die RHS aus. Ansonsten sind sie in einer ifAussage gleichwertig .

Das einzige Mal, wenn ich einen Nutzen aus der Verwendung von Nicht-Kurzschluss-Operatoren ziehen kann, ist, dass die RHS eine Art von erwünschtem Nebeneffekt aufweist, den Sie auf jeden Fall haben möchten. Ich kann mir kein konkretes Beispiel vorstellen, an dem Sie dies wünschen würden, und ich glaube nicht, dass es eine gute Praxis ist, aber das ist der Unterschied.

Jonathan
quelle
1
+1. Genau richtig, wenn boolesche und logische Operatoren bitweise verglichen werden, wird immer dasselbe Ergebnis zurückgegeben, aber (zumindest in Java und C #) nur die logischen Operatoren kurzgeschlossen.
Steve
Danke für die Antwort. Ihr Absatz 1 war das, worauf ich in meinem Absatz 4 abzielte, indem ich sagte, dass bitweise ein eifriger Operator ist, während sich die Bedingung wie ein Kurzschluss verhält . Ihr Absatz 2 ist das Anliegen, das ich in meinem Absatz 5 beschrieben habe. Daher ist mir der Unterschied bewusst, aber ich suche nach diesem speziellen Beispiel, an das weder Sie noch ich denken können.
Deerasha
7

Die allgemeine philosophische Antwort lautet, dass die Verwendung bitweiser Operatoren für boolesche Operatoren untypisch ist und das Lesen des Codes erschwert. In der Praxis (für Code, der sich in der Produktion befindet) ist besser lesbarer Code einfacher zu warten und daher wünschenswerter.

Informationen zur tatsächlichen Verwendung des Bedarfs an Kurzschlussbetreibern finden Sie in den folgenden Fällen:

if (args.length > 0 && args[0] == 'test') ....

if (b != NULL && b.some_function()) ...

if (b == NULL || b.some_function()) ...

Diese Art von Operationen wird häufig im Code der realen Welt angezeigt.

Kathy Van Stone
quelle
Tfa. Wie erkläre ich meinen 15-Jährigen, dass 1 &schwerer zu lesen ist als 2? Ich habe kein Beispiel, in dem die 2 Operatoren für Boolesche Operanden nicht auf die gleiche Weise funktionieren. Ich stimme Ihrer Meinung zu, dass Code lesbarer und leichter zu warten ist. Ich möchte sie ermutigen, schönen Code zu schreiben. Aber einen Beweis in meiner Werkzeugtasche zu haben, wäre überzeugender als „weil ich es gesagt habe“. Ich habe es als Standard bei diesem Link angegeben und muss mich möglicherweise darauf verlassen, wenn ich nicht das Beispiel bekomme, das ich suche. Wie ich @Steve Haigh fragte: Sollte Java dies als missbräuchliche Verwendung anzeigen?
Deerasha
@ Deerasha Ich dachte eher an einen Streit mit deinem Mentor. Versuchen Sie für die Klasse nicht einmal, ihnen mitzuteilen, dass Sie für logische Bedingungen bitweise Operatoren verwenden können.
Kathy Van Stone
4

Sie verwenden bitweise Operatoren, wenn Sie Bitmasken-Enumerationen vergleichen. Sie haben beispielsweise eine Aufzählung von Zuständen und ein Objekt, das sich in mehr als einem dieser Zustände befinden kann. In diesem Fall müssen Sie Ihrem Objekt bitweise oder mehr als einen Status zuweisen.

zum Beispiel state = CONNECTED | IN_PROGRESSwo CONNECTED could be 0x00000001undIN_PROGRESS 0x00000010

Weitere Informationen finden Sie in der Dokumentation der Flaggenlisten.

pwny
quelle
Dank dir habe ich eine Anwendung von bitweisen Operatoren gelernt, die ich vorher nicht gekannt hatte! In diesem Beispiel gilt jedoch nur der bitweise Operator. Ich suche nach einem gut geschriebenen Code, bei dem die Verwendung des bitweisen Codes anstelle des bedingten Codes zur Kompilierung, aber zu einer falschen Ausgabe führen würde. Das heißt, wenn ein solches Code-Snippet existiert.
Deerasha
Ich glaube nicht, dass das in Java passieren kann, da ich glaube, dass man das | nennt oder & Operatoren für Werte, die nicht bitweise sein können und die oder nur eine logische | ausführen oder &. Ich kann mich nicht erinnern, ob dies in Java der Fall ist, aber ich weiß genau, ob dies in C # MSDN der Fall ist: "Binäroperatoren sind für die Integraltypen und bool vordefiniert. Berechnet für Integraltypen das bitweise ODER seiner Operanden bool operands, | berechnet das logische ODER seiner Operanden "
pwny
Nach einigen weiteren Nachforschungen fand ich heraus, dass der einzige Unterschied zwischen | und || und & und && für boolesche Operanden in Java ist das Kurzschlussverhalten, sodass das von Ihnen beschriebene Szenario nicht wirklich möglich ist.
Pwny
0

ein einfacheres Beispiel für Unrecht:

int condA=1, condB=2;

if (condA!=0 && condB!=0) {
    // correct!
}
if ((condA & condB)!=0) {
    // never executed
}

Hier haben Sie zwei Bedingungen, beide sind nicht Null; aber das bitweise &ergibt null.

Javier
quelle
@Javier: Danke, dass du geantwortet hast, aber ich bin ein bisschen verwirrt. Ich arbeite in Java und dieser Code wird nicht kompiliert. (condA && condB)fehler, da das && für 2 ints nicht funktioniert , nur 2 booleans. (condA & condB)Solange es korrekt ist, int ergibt es ein und in Java können wir nicht sagen, if(int)dass es auch fehlerhaft ist. Du bist der erste, der versteht, wonach ich suche - genau das Beispiel für Unrecht .
Deerasha
(Boolean(condA) && Boolean(condB)) Ich habe Java schon lange nicht mehr benutzt ... try (ich denke, es Boolean(x)ist truefür Ganzzahlen ungleich Null, oder?)
Javier
Nope @Javier: Kann nicht von int in boolean umgewandelt werden.
Deerasha
was ist ((condA!=0) && (condB!=0))?
Javier
@ Javier yay es kompiliert, aber die "Unrichtigkeit" wird nicht mehr dargestellt if (((condA!=0) && (condB!=0))) { System.out.println("correct"); } if (((condA!=0) & (condB!=0))) { System.out.println("never executed?"); }führt beide print-Anweisungen aus.
Deerasha