Bedingte XOR?

84

Wie kommt es, dass C # keinen bedingten XOROperator hat?

Beispiel:

true  xor false = true
true  xor true  = false
false xor false = false
Gilad Naaman
quelle
15
Wie !=arbeitet man als Ersatz?
Pascal Cuoq
45
C # hat einen xor-Operator (x ^ y). Ich bestreite daher die Prämisse der Frage. Können Sie erklären, warum Sie geglaubt haben, dass C # keinen xor-Operator hat? Ich bin interessiert zu erfahren, warum Leute falsche Dinge über C # glauben.
Eric Lippert
3
@ Eric Lippert: Ich denke, er bezieht sich auf logische Operatoren ( & | ^) und bedingte Operatoren ( && ||). Aber Sie haben Recht (natürlich), es gibt eine logische XOR ...
BoltClock
14
@BoltClock: Oh, wenn die Frage lautet "Warum gibt es keinen kurzgeschlossenen xor-Operator?" - wie könnte es sein? Mit "und", wenn das erste Argument falsch ist, müssen Sie das zweite nicht auswerten. Wenn mit "oder" das erste Argument wahr ist, müssen Sie das zweite nicht bewerten. Sie müssen immer beide Argumente für xor auswerten, damit kein Kurzschluss möglich ist.
Eric Lippert
4
Die Frage selbst ist besser für Microsoft geeignet - und das ist ein guter Grund für eine Ablehnung -, aber wenn jemand sie wegen des Operators ^ abgelehnt hat, müssen Sie sie mit mehr Liebe zum Detail lesen, da die Frage an Bedingungen geknüpft war. logisch, nicht einfach "warum gibt es kein XOR".
The Evil Greebo

Antworten:

118

In C # führen bedingte Operatoren ihren sekundären Operanden nur bei Bedarf aus .

Da ein XOR per Definition beide Werte testen muss , wäre eine bedingte Version dumm.

Beispiele :

  • Logisches UND: &- testet jedes Mal beide Seiten.

  • Logisches ODER: |- Testen Sie jedes Mal beide Seiten.

  • Bedingtes UND: &&- testet die 2. Seite nur, wenn die 1. Seite wahr ist.

  • Bedingtes ODER: ||- Testen Sie die 2. Seite nur, wenn die 1. Seite falsch ist.

Der böse Griechisch
quelle
34
Ein XOR-Operator würde nicht gegen die Konvention verstoßen: "Bedingte Operatoren führen ihren sekundären Operanden nur bei Bedarf aus". Es wäre einfach immer notwendig.
Nathan Kovner
2
Bedingtes XOR könnte eine nette und elegante Abkürzung für bestimmte Muster sein, obwohl es nicht sicher ist, ob es gerechtfertigt genug ist, um es in die Sprache aufzunehmen. Ein Beispiel für solche Muster, bei denen sich XOR als nützlich erweisen könnte, ist die bedingte Negation: Wenn ein Boolescher Ausdruck bei einem zweiten Booleschen Ausdruck negiert werden soll oder nicht.
SalvadorGomez
1
Ich habe seit einiger Zeit nicht mehr darauf geantwortet, aber um auf den populären Kommentar von @KhyadHalda zu antworten: Warum sollten Sie jemals etwas bauen, von dem Sie wissen, dass es niemals verwendet werden würde? Sie würden absichtlich toten Code schreiben.
The Evil Greebo
Angesichts der Tatsache, dass ein bedingter XOR-Operator nicht gegen die von Ihnen definierte Konvention verstoßen würde (Khyads Kommentar), und der Tatsache, dass er in einigen Fällen tatsächlich nützlich wäre, wird jede "Albernheit", die Sie einem solchen existierenden Operator zuschreiben, so gut wie negiert.
Syndog
1
Wie wäre ein bedingter XOR jemals nützlich? Ein bedingter XOR kann niemals auswerten, ohne beide Seiten zu vergleichen, um festzustellen, ob sie gleich sind oder nicht. Selbst die Vorstellung eines bedingten XOR, der zwei Bools vergleicht, muss den Wert jedes Bools überprüfen und die Gleichheit testen.
The Evil Greebo
277

Frage ist etwas veraltet, aber ...

So sollte dieser Operator funktionieren:

true xor false = true
true xor true = false
false xor true = true
false xor false = false

So funktioniert der Operator! = Mit Bool-Typen:

(true != false) // true
(true != true) // false
(false != true) // true
(false != false) // false

Wie Sie sehen, ^^kann nicht vorhandenes durch vorhandenes ersetzt werden!=

piotrpo
quelle
46
Dies ist tatsächlich die einzige Antwort, die die Frage direkt und richtig beantwortet.
usr
39
Ich sitze hier und mache mir selbst klar, dass ich nicht wusste, dass !=das funktionieren würde.
AdamMc331
1
Die Antwort ist richtig, die Kommentare jedoch nicht. Die Frage "Warum hat C # kein bedingtes XOR?" Wird nicht behandelt. Genau genommen ist dies kein logischer Operator, sondern ein relationaler Gleichheitsoperator. Das Ergebnis ist zwar dasselbe wie XOR, es befindet sich jedoch in einer anderen Klasse. Es wird nur mit XOR verglichen, wenn zwei boolesche Werte getestet werden, und beide Seiten des Operators müssen noch ausgewertet werden.
The Evil Greebo
3
@TheEvilGreebo - Was Sie sagen, ist wahr; Der Operator! = ist technisch gesehen kein bedingter XOR-Operator. In dieser Antwort heißt es jedoch effektiv: "Ein bedingter XOR-Operator existiert nicht, weil der Operator! = Dies tut." So habe ich es jedenfalls gelesen.
Syndog
6
Ich denke, so ziemlich jeder, der zu diesem Beitrag gekommen ist, wollte eigentlich XOR auf Booleans schreiben. als gäbe es logisch ANDund ORdoch nichts als XOR. oder zumindest haben wir nicht realisiert !=:) @TheEvilGreebo
M.kazem Akhgary
31

Es gibt den logischen XOR-Operator: ^

Dokumentation: C # -Operatoren und ^ Operator

iceaway
quelle
2
Logisch, nicht bedingt. Logisch und = &, bedingt und = &&. Er fragt nach Bedingt.
The Evil Greebo
3
Es ist binär, nicht logisch. Es wird davon ausgegangen, dass Bools entweder 0 oder 1 sind, was in der CLR nicht zutrifft.
usr
1
Entschuldigung, diese Antwort beantwortet die Frage nach den CONDITIONAL-Operatoren nicht wirklich. Dies ist ein bisschen opperator
Nathan Tregillus
2
Für den Datensatz wird in der in dieser Antwort verknüpften Dokumentation ausdrücklich angegeben, dass es ^sich bei Verwendung mit booleschen Operanden um einen booleschen Operator handelt. "Für die Bool-Operanden berechnet der Operator ^ das gleiche Ergebnis wie der Ungleichungsoperator! =". Sie können auch bitweise x oder ganzzahlige Operanden mit verwenden ^. C # ist nicht C.
15ee8f99-57ff-4f92-890c-b56153
24

Zur Verdeutlichung arbeitet der Operator ^ sowohl mit integralen Typen als auch mit bool.

Siehe ^ Operator ^ von MSDN (C # -Referenz) :

Binäre ^ Operatoren sind für die Integraltypen und bool vordefiniert. Für integrale Typen berechnet ^ das bitweise Exklusiv-ODER seiner Operanden. Für Bool-Operanden berechnet ^ das logische Exklusiv-Oder seiner Operanden. Das Ergebnis ist genau dann wahr, wenn genau einer seiner Operanden wahr ist.

Möglicherweise hat sich die Dokumentation seit 2011 geändert, als diese Frage gestellt wurde.

RichardCL
quelle
2
habe lange in c # programmiert, wusste das nie! danke @RichardCL!
Nathan Tregillus
Dies ist eine gute Information, scheint aber als Kommentar oder Bearbeitung der anderen Antwort, ^die diese erwähnt und um fünf Jahre älter ist, angemessener zu sein . Ich bezweifle, dass sich etwas geändert hat.
Chris
13

Wie von Mark L gefragt , ist hier die richtige Version:

 Func<bool, bool, bool> XOR = (X,Y) => ((!X) && Y) || (X && (!Y));

Hier ist die Wahrheitstabelle:

 X | Y | Result
 ==============
 0 | 0 | 0
 1 | 0 | 1
 0 | 1 | 1
 1 | 1 | 0

Referenz: Exklusiv ODER

Einfacher Kerl
quelle
2
Die gestellte Frage war, WARUM C # keinen bedingten XOR-Operator hat. Dies beantwortet die Frage nicht. Was die Funktion selbst betrifft: Diese Funktion arbeitet als bedingtes XOR - die Frage ist jedoch, ob sie effizienter ist als das nicht bedingte XOR. Um die ausschließliche Wahrheit zu testen, muss XOR bestätigen, dass ein und genau ein Ergebnis wahr ist. Dies bedeutet, dass beide Seiten bewertet und verglichen werden müssen. Die obige Funktion testet beide Seiten einer und Bedingung und invertiert dabei mindestens einen Wert. Wissen wir intern, ob dies anders ist als XOR?
The Evil Greebo
6

Oh ja, das tut es.

bool b1 = true;
bool b2 = false;
bool XOR = b1 ^ b2;
Armen Tsirunyan
quelle
1
Es ist ein binärer Operator, kein logischer. Es wird davon ausgegangen, dass Bools entweder 0 oder 1 sind, was in der CLR nicht zutrifft. Dieser Code kann also tatsächlich nicht funktionieren.
usr
6
@usr, In C # ist der Operator ^ logisch, wenn er auf zwei boolesche Operanden angewendet wird. Sie haben durch diese Antworten sehr viel kommentiert. Haben Sie jemals Code ausgeführt, um Ihre Hypothese zu testen?
Marc L.
2
@MarcL. Ich habe: pastebin.com/U7vqpn6G Gibt true aus, obwohl true ^ true falsch sein soll. bool ist nicht immer gleich 0 oder 1. Es ist kein logischer Typ in der CLR. Es ist eine 8-Bit-Menge mit beliebigem Inhalt. Ich hätte eine überprüfbare IL generieren können, um das Problem ebenfalls zu demonstrieren.
usr
2
Wenn Sie beispielsweise andere CLR-Sprachen als C # verwenden. Ich wiederhole: Ich hätte ILASM verwenden können, um eine vollständig überprüfbare, sichere Assembly zu erstellen, die dies tut (auf IL-Ebene ist ein boolescher Wert nur ein i1, genau wie ein Byte). Dies ist ein zu 100% definiertes und sicher verwaltetes Verhalten. Die CLR ist nicht aufgeraut.; Das erste Mal, dass ich dieses Verhalten sah, war bei Verwendung von Microsoft Pex.
usr
1
@ EdPlunkett, ich glaube nicht, dass dein Truck bei mir ist. usr hat gezeigt, dass es sich intern tatsächlich um einen binären Operator handelt. Der "Missbrauch", über den ich mich beschwert habe, war das Mittel, mit dem er es bewiesen hat, was ich immer noch behaupte, ist zu nervös. Es kann passieren, aber die Verwendung von Boolean wird so gründlich in das Niemandsland gebracht, dass die Bereitstellung als CLR-sicher im besten Fall gefährlich, im schlimmsten Fall missbräuchlich (wenn nicht böswillig) wäre und als Fehler behandelt werden sollte. Was usr beweist, ist, dass intern C # eher C ähnelt, als jeder von uns gedacht hat. Ob Code, der dies tut, als gültig angesehen werden sollte, ist eine andere Frage.
Marc L.
4

Bedingtes xor existiert nicht, aber Sie können logisches verwenden, da xor für Boolesche Werte definiert ist und alle bedingten Vergleiche zu Booleschen Werten ausgewertet werden.

Sie können also etwas sagen wie:

if ( (a == b) ^ (c == d))
{

}
Klark
quelle
Es ist ein binärer Operator, kein logischer. Es wird davon ausgegangen, dass Bools entweder 0 oder 1 sind, was in der CLR nicht zutrifft. Dieser Code kann also tatsächlich nicht funktionieren.
usr
@usr was meinst du mit CLR? Dies funktionierte für mich, nicht sicher, ob ich hier einen
Randfall
3
@Spencevail Sie haben wahrscheinlich nicht über den Fall nachgedacht, dass ein nicht falscher Boolescher Wert möglicherweise keine ganzzahlige Darstellung hat 1. Dies ist eine wenig bekannte Tatsache. Sie können in eine Situation geraten, in der das xor von zwei nicht falschen Booleschen Werten immer noch nicht falsch ist! Das heißt, in diesem speziellen Code wird der xor-Operator immer nur auf Werte in [0,1] angewendet, so dass mein Kommentar nicht (vollständig) gilt.
usr
1
@Spencevail das ist genau der Fall, der fehlschlagen kann. Es ist möglich, eine sichere verwaltete Codefunktion CreateBool (Byte) zu erstellen, die ein Byte in einen Bool mit denselben Bits konvertiert. Dann ist CreateBool (1) ^ CreateBool (2) wahr, aber CreateBool (1) ist wahr und CreateBool (2) ist auch wahr! &ist auch anfällig.
usr
1
Eigentlich habe ich gerade einen RyuJIT-Fehler gemeldet, weil sie diese Möglichkeit nicht in Betracht gezogen und kompiliert haben, &&als wäre es &eine Fehlkompilierung.
usr
3

Während es einen logischen xor-Operator ^gibt, gibt es keinen bedingten xor-Operator. Sie können ein bedingtes xor von zwei Werten A und B erreichen, indem Sie Folgendes verwenden:

A ? (!B) : B

Die Parens sind nicht notwendig, aber ich habe sie der Klarheit halber hinzugefügt.

Wie The Evil Greebo hervorhebt, bewertet dies beide Ausdrücke, aber xor kann nicht wie und und oder kurzgeschlossen werden .

Jimreed
quelle
Was ist der Unterschied zwischen einem Logikaner und einem Bedingten? oO
Armen Tsirunyan
@Armen Tsirunyan Die logischen Operatoren führen bitweise Operationen in Typen aus, in denen dies sinnvoll ist, während die bedingten Operatoren boolesche Werte verarbeiten und ein boolesches Ergebnis zurückgeben. Boolesche Werte berücksichtigen: 0101 ^ 0011hat den Wert 0110.
Jimreed
3
Nein, du liegst völlig falsch. In C # gibt es beide Arten von XORs (sie werden bitweise bzw. logisch genannt). Beide verwenden das Symbol ^.
Armen Tsirunyan
1

Sie können verwenden:

a = b ^ c;

genau wie in c / c ++

Gulyan
quelle
0

Bedingtes (kurzgeschlossenes) XOR gibt es nicht. Bedingte Operatoren sind nur dann sinnvoll, wenn es eine Möglichkeit gibt, das Endergebnis endgültig zu bestimmen, wenn nur das erste Argument betrachtet wird. XOR (und Addition) erfordern immer zwei Argumente, sodass nach dem ersten Argument kein Kurzschluss möglich ist.

Wenn Sie A = wahr kennen, dann ist (A XOR B) =! B.

Wenn Sie A = falsch kennen, dann ist (A XOR B) = B.

In beiden Fällen, wenn Sie A kennen, aber nicht B, dann wissen Sie nicht genug, um es zu wissen (A XOR B). Sie müssen immer die Werte von A und B lernen, um die Antwort zu berechnen. Es gibt buchstäblich keinen Anwendungsfall, in dem Sie das XOR jemals ohne beide Werte auflösen können.

Beachten Sie, dass XOR per Definition vier Fälle hat:

false xor true  = true
true  xor false = true
true  xor true  = false
false xor false = false

Wiederum ist aus den obigen Ausführungen hoffentlich ersichtlich, dass die Kenntnis des ersten Werts niemals ausreicht, um die Antwort zu erhalten, ohne auch den zweiten Wert zu kennen. In Ihrer Frage haben Sie jedoch den ersten Fall weggelassen. Wenn du stattdessen wolltest

false op true  = false (or DontCare)
true  op false = true
true  op true  = false
false op false = false

dann können Sie das tatsächlich durch eine kurzschließende bedingte Operation erhalten:

A && !B

Aber das ist kein XOR.

Kevin Holt
quelle
Ich sehe in dieser Antwort nichts, was nicht in mindestens einer Antwort oben enthalten ist. Ich sehe keinen Hinweis darauf, dass Ihr kurzschlussfreies Un-XOR das ist, wonach OP gesucht hat, da er eine Antwort akzeptiert hat, die davon ausgeht, dass er das richtige XOR wollte.
15ee8f99-57ff-4f92-890c-b56153
Meine ist buchstäblich die einzige Antwort, die bisher vorgeschlagen wurde und die die angeforderte Wahrheitstabelle des OP erstellen kann, ohne das zweite Argument zu bewerten.
Kevin Holt
Das OP fragte auch, warum es kein bedingtes XOR gibt, und während die obigen Antworten richtig aussagen, dass XOR zwei Argumente erfordert, schienen die obigen Antworten IMO nicht ausreichend zu erklären, WARUM XOR tatsächlich zwei Argumente benötigt. Natürlich fühlen Sie sich anders, aber für mich war aus den verschiedenen Kommentaren auf dieser Seite ersichtlich, dass die grundlegende Zwei-Argumentation von XOR einem vollständigen Anfänger noch nicht vollständig erklärt worden war.
Kevin Holt
1
Du hast mich dazu überredet.
15ee8f99-57ff-4f92-890c-b56153
@ Kevin Holt - Logisches XOR ist sinnvoll, wenn eine der Bedingungen erfüllt sein muss, aber nicht beide. Dass Sie beide Bedingungen bewerten müssen, spielt keine Rolle. Der Kurzschluss ist ein Detail auf niedriger Ebene, über das Sie sich nur Gedanken machen müssen, wenn Sie mit leistungskritischem Code arbeiten (der Kontrollfluss ist langsam). Ich würde mich mehr darum kümmern, was "exklusiv oder" bedeuten soll, wenn ich einen logischen Operator daraus mache. Lassen Sie es nämlich wie die bitweise Version (wie die anderen Operatoren) funktionieren oder machen Sie es zu einer oder einer exklusiven Version (so viele Bedingungen, wie Sie möchten, aber nur eine kann wahr sein).
Thorham
-3

Diese Frage wurde affektiv beantwortet, aber ich bin auf eine andere Situation gestoßen. Es ist wahr, dass keine bedingte XOR erforderlich ist. Es ist auch wahr, dass der Operator ^ verwendet werden kann. Wenn Sie jedoch nur den Status "true || false" der Operanden testen müssen, kann ^ zu Problemen führen. Beispielsweise:

void Turn(int left, int right)
{
    if (left ^ right)
    {
        //success... turn the car left or right...
    }
    else
    {
        //error... no turn or both left AND right are set...
    }
}

In diesem Beispiel wird der Zweig "Erfolg" eingegeben, wenn links auf 10 (0xa) und rechts auf 5 (0x5) gesetzt ist. In diesem (simplen, wenn auch albernen) Beispiel würde dies zu einem Fehler führen, da Sie nicht gleichzeitig nach links und rechts abbiegen sollten. Was ich vom Fragesteller erfahren habe, ist nicht, dass er tatsächlich eine Bedingung wollte, sondern eine einfache Möglichkeit, das Wahr / Falsch für die an xor übergebenen Werte auszuführen.

Ein Makro könnte den Trick machen:

#define my_xor(a, b) ( ((a)?1:0) ^ ((b)?1:0) )

Fühlen Sie sich frei, mich herumzuschlagen, wenn ich daneben bin: o)

Ich habe Jimreeds Antwort unten gelesen, nachdem ich dies gepostet habe (schlechter Yapdog!) Und seine ist tatsächlich einfacher. Es würde funktionieren und ich habe absolut keine Ahnung, warum seine Antwort abgelehnt wurde ...

Yap Hund
quelle
3
Dies ist eine C # -Frage, nicht C / C ++. iferfordert einen booleschen Ausdruck, der nicht einmal mit einem int kompiliert werden kann.
Marc L.