XOR condizionale?


89

Come mai C # non ha un XORoperatore condizionale ?

Esempio:

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

15
Come !=funziona come sostituto?
Pascal Cuoq

45
C # ha avere un operatore xor (x ^ y). Nego quindi la premessa della domanda. Puoi spiegare perché hai creduto che C # non avesse un operatore xor? Mi interessa sapere perché le persone credono in cose false su C #.
Eric Lippert

3
@Eric Lippert: Penso che si riferisca agli operatori logici ( & | ^) e agli operatori condizionali ( && ||). Ma hai ragione (ovviamente), c'è uno XOR logico ...
BoltClock

14
@BoltClock: Oh, se la domanda è "perché non c'è nessun operatore xor in cortocircuito?" - come potrebbe esserci? Con "e" se il primo argomento è falso non è necessario valutare il secondo. Con "o", se il primo argomento è vero, non è necessario valutare il secondo. È sempre necessario valutare entrambi gli argomenti per xor, quindi non è possibile alcun cortocircuito.
Eric Lippert

4
La domanda in sé è più adatta a Microsoft - e quindi questo è un buon motivo per downvote - ma se chi ha downvote lo ha fatto a causa dell'operatore ^, allora devi leggere con maggiore attenzione ai dettagli, perché la domanda era condizionale vs. logico, non semplicemente "perché non c'è uno XOR".
The Evil Greebo

Risposte:


124

In C #, gli operatori condizionali eseguono l'operando secondario solo se necessario .

Poiché uno XOR deve per definizione testare entrambi i valori, una versione condizionale sarebbe sciocca.

Esempi :

  • AND logico: &- testa ogni volta entrambi i lati.

  • OR logico: |- prova entrambi i lati ogni volta.

  • AND condizionale: &&- verifica il 2 ° lato solo se il 1 ° lato è vero.

  • Condizionale OR: ||- testare il 2 ° lato solo se il 1 ° lato è falso.


37
Un operatore XOR non violerebbe la convenzione "gli operatori condizionali eseguono il loro operando secondario solo se necessario". Sarebbe solo sempre necessario.
Nathan Kovner

2
Lo XOR condizionale potrebbe essere una scorciatoia piacevole ed elegante per alcuni modelli particolari, sebbene non sia sicuro se sufficientemente giustificato da includerlo nella lingua. Un esempio di tali modelli in cui XOR potrebbe rivelarsi utile è la negazione condizionale: quando un'espressione booleana deve essere negata o meno, data una seconda espressione booleana.
SalvadorGomez

1
Non ho risposto a questo per un po 'di tempo, ma per rispondere al commento popolare di @KhyadHalda: Perché mai dovresti costruire qualcosa che sai non sarebbe mai stato utilizzato? Scriveresti deliberatamente codice morto.
The Evil Greebo

2
In che modo, mai, sarebbe mai utile uno XOR condizionale? Uno XOR condizionale non può mai valutare senza confrontare entrambi i lati per determinare che sono o non sono uguali. Anche la nozione di un XOR condizionale che confronta due bool deve ancora controllare il valore di ogni bool e testare l'uguaglianza.
The Evil Greebo

1
È sciocco come un operatore di addizione condizionale. Perché non creare un altro operatore per l'addizione condizionale, dove (a + b) valuta b solo quando b è necessario? Proprio come con XOR condizionale, questo non violerebbe la convenzione degli operatori condizionali, è solo che il secondo argomento sarebbe sempre necessario. Non c'è mai un caso d'uso per questo. E non sono solo pedante con questo esempio: l'operazione XOR è essenzialmente un'aggiunta a 1 bit.
Kevin Holt

283

La domanda è un po 'datata ma ...

Ecco come dovrebbe funzionare questo operatore:

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

Ecco come l'operatore! = Funziona con i tipi bool:

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

Quindi, come vedi, inesistente ^^può essere sostituito con esistente!=


46
Questa è in realtà l'unica risposta che affronta la domanda in modo diretto e corretto.
usr

40
Sono seduto qui facepalming me stesso che non sapevo !=avrebbe funzionato per questo.
AdamMc331

1
La risposta è corretta ma i commenti no. Non risponde alla domanda, che è "perché C # non ha un XOR condizionale?". A rigor di termini questo non è un operatore logico, è un operatore di uguaglianza relazionale. Sebbene il risultato sia lo stesso di XOR, è in una classe diversa. Viene confrontato con XOR solo durante il test di due valori booleani ed entrambi i lati dell'operatore devono ancora essere valutati.
The Evil Greebo

3
@TheEvilGreebo - Quello che dici è vero; l'operatore! = non è tecnicamente un operatore XOR condizionale. Tuttavia, questa risposta dice effettivamente: "Un operatore XOR condizionale non esiste perché l'operatore! = Esiste". Comunque è così che l'ho letto.
Syndog

6
Penso che praticamente tutti alla fine di questo post volessero scrivere XOR su Booleans. come se ci fosse logico ANDe ORma niente come XOR. o almeno non ce ne siamo resi conto !=:) @TheEvilGreebo
M.kazem Akhgary

30

C'è l'operatore XOR logico: ^

Documentazione: operatori C # e operatore ^


2
Logico, non condizionale. Logico e = &, condizionale e = &&. Chiede del condizionale.
The Evil Greebo

3
È binario, non logico. Si presuppone che i valori bool siano 0 o 1, il che non è vero in CLR.
usr

1
spiacenti, questa risposta in realtà non risponde alla domanda sugli operatori CONDIZIONALI. questo è un po 'opprimente
Nathan Tregillus

3
Per la cronaca, la documentazione collegata in questa risposta afferma esplicitamente che ^, quando viene utilizzato con operandi booleani, è un operatore booleano. "per gli operandi bool, l'operatore ^ calcola lo stesso risultato dell'operatore di disuguaglianza! =". È inoltre possibile utilizzare operandi interi xo bit per bit con ^. C # non è C.
15ee8f99-57ff-4f92-890c-b56153

25

A titolo di chiarimento, l'operatore ^ funziona sia con i tipi integrali che con bool.

Vedere l'operatore ^ di MSDN (riferimenti per C #) :

Gli operatori binari ^ sono predefiniti per i tipi integrali e bool. Per i tipi integrali, ^ calcola l'OR esclusivo bit per bit dei suoi operandi. Per gli operandi bool, ^ calcola l'esclusiva logica-or dei suoi operandi; ovvero, il risultato è vero se e solo se esattamente uno dei suoi operandi è vero.

Forse la documentazione è cambiata dal 2011 quando è stata posta questa domanda.


2
programmavo da molto tempo in c #, non lo sapevo! grazie @RichardCL!
Nathan Tregillus

Questa è una buona informazione ma sembra più appropriata come commento o modifica all'altra risposta che la menziona ^e la precede di cinque anni. Dubito che sia cambiato qualcosa.
Chris

13

Come chiesto da Mark L , ecco la versione corretta:

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

Ecco la tabella della verità:

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

Riferimento: OR esclusivo


2
La domanda posta era PERCHÉ C # non ha un operatore XOR condizionale. Questo non risponde alla domanda. Per quanto riguarda la funzione stessa: questa funzione opera come XOR condizionale - tuttavia la domanda è: è più efficiente dello XOR non condizionale? Per verificare la verità esclusiva, XOR deve confermare che un solo risultato è vero. Ciò significa che entrambi i lati devono essere valutati e confrontati. La funzione sopra verifica entrambi i lati di una condizione e invertendo almeno un valore. Sappiamo internamente se questo è diverso da XOR?
The Evil Greebo

6

Oh sì, lo fa.

bool b1 = true;
bool b2 = false;
bool XOR = b1 ^ b2;

1
È un operatore binario, non logico. Si presuppone che i valori bool siano 0 o 1, il che non è vero in CLR. Quindi questo codice può effettivamente non funzionare.
usr

6
@usr, in C #, l'operatore ^ è logico se applicato a due operandi booleani. Hai commentato moltissimo attraverso queste risposte, hai mai eseguito un codice per testare la tua ipotesi?
Marc L.

2
@ MarcL. L'ho fatto: pastebin.com/U7vqpn6G Stampa true, sebbene true ^ true dovrebbe essere falso. bool non è sempre uguale a 0 o 1. Non è un tipo logico in CLR. È una quantità a 8 bit con contenuti arbitrari. Avrei anche potuto generare IL verificabile per dimostrare il problema.
usr

2
Ad esempio, quando si utilizzano linguaggi CLR diversi da C #. Ripeto: avrei potuto usare ILASM per creare un assembly completamente verificabile e sicuro che fa questo (a livello IL un valore booleano è solo un i1, proprio come un byte). Questo è un comportamento definito al 100% e gestito in modo sicuro. Il CLR non è maltrattato .; La prima volta che ho visto questo comportamento è stato quando utilizzavo Microsoft Pex.
usr

1
@EdPlunkett, non credo che il tuo camion sia con me. usr ha mostrato che internamente è in effetti un operatore binario . L '"abuso" di cui mi sono lamentato è stato il mezzo con cui lo ha dimostrato, che continuo a ritenere troppo tagliente. Può accadere, ma mette l'uso di Boolean così completamente nella terra di nessuno che distribuirlo come CLR-safe sarebbe pericoloso nel migliore dei casi, abusivo (se non dannoso) nel peggiore, e dovrebbe essere trattato come un bug. Ciò che usr dimostra è che internamente C # è più simile a C di quanto ognuno di noi pensasse. Se il codice che fa questo debba essere considerato valido è un'altra questione.
Marc L.

4

Lo xor condizionale non esiste, ma puoi usarne uno logico perché xor è definito per booleani e tutti i confronti condizionali vengono valutati come booleani.

Quindi puoi dire qualcosa come:

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

}

È un operatore binario, non logico. Si presuppone che i valori bool siano 0 o 1, il che non è vero in CLR. Quindi questo codice può effettivamente non funzionare.
usr

@usr cosa intendi CLR? Questo ha funzionato per me, non sono sicuro di aver perso un caso limite qui ...
LunaCodeGirl

3
@ Spencevail probabilmente non stavi pensando al caso in cui un booleano non falso potrebbe non avere una rappresentazione intera 1. Questo è un fatto poco noto. Puoi finire in una situazione in cui lo xor di due booleani non falsi è ancora non falso! Detto questo, in questo particolare codice l'operatore xor viene applicato solo ai valori in [0,1] in modo che il mio commento non si applichi (completamente).
usr

1
@ Spencevail che è esattamente il caso che può fallire. È possibile creare una funzione di codice gestito sicuro CreateBool (byte) che converte un byte in un bool degli stessi bit. Quindi, CreateBool (1) ^ CreateBool (2) è vero, ma CreateBool (1) è vero e anche CreateBool (2) è vero! &è anche vulnerabile.
usr

1
In realtà, ho appena segnalato un bug di RyuJIT perché non hanno considerato questa possibilità e compilato &&come se fosse &un errore di compilazione.
usr

3

Sebbene sia presente un operatore xor logico^ , non esiste un operatore xor condizionale . È possibile ottenere uno xor condizionale di due valori A e B utilizzando quanto segue:

A ? (!B) : B

Le parentesi non sono necessarie, ma le ho aggiunte per chiarezza.

Come sottolineato da The Evil Greebo, questo valuta entrambe le espressioni, ma xor non può essere cortocircuitato come and and or .


Qual è la differenza tra un logico ^ e un condizionale ^? oO
Armen Tsirunyan

@Armen Tsirunyan Gli operatori logici eseguono operazioni bit per bit nei tipi in cui ciò ha senso, mentre gli operatori condizionali operano su valori booleani e restituiscono un risultato booleano. Considerando i valori booleani: 0101 ^ 0011ha il valore 0110.
jimreed

3
no, ti sbagli completamente. ci sono entrambi i tipi di XOR (sono chiamati rispettivamente bit a bit e logico) in C #. Entrambi usano il simbolo ^.
Armen Tsirunyan

1

Puoi usare:

a = b ^ c;

proprio come in c / c ++


0

Non esiste XOR condizionale (cortocircuito). Gli operatori condizionali sono significativi solo quando c'è un modo per dire in modo definitivo il risultato finale guardando solo il primo argomento. XOR (e l'addizione) richiedono sempre due argomenti, quindi non c'è modo di cortocircuitare dopo il primo argomento.

Se sai A = vero, allora (A XOR B) =! B.

Se conosci A = false, allora (A XOR B) = B.

In entrambi i casi, se conosci A ma non B, allora non sai abbastanza per sapere (A XOR B). Devi sempre imparare i valori di A e B per calcolare la risposta. Non esiste letteralmente alcun caso d'uso in cui è possibile risolvere XOR senza entrambi i valori.

Tieni presente che XOR per definizione ha quattro casi:

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

Ancora una volta, si spera che sia ovvio da quanto sopra che conoscere il primo valore non è mai sufficiente per ottenere la risposta senza conoscere anche il secondo valore. Tuttavia, nella tua domanda, hai omesso il primo caso. Se invece lo volessi

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

allora puoi davvero ottenerlo con un'operazione condizionale di cortocircuito:

A && !B

Ma non è uno XOR.


Non vedo nulla in questa risposta che non sia in almeno una risposta sopra. Non vedo alcuna indicazione che il tuo un-xor cortocircuitabile sia ciò che OP stava cercando, dal momento che ha accettato una risposta che presume che volesse il corretto xor.
15ee8f99-57ff-4f92-890c-b56153

La mia è letteralmente l'unica risposta suggerita finora che può produrre la tabella di verità richiesta dall'OP senza valutare il secondo argomento.
Kevin Holt

Anche l'OP ha chiesto perché non esiste uno XOR condizionale, e mentre le risposte sopra dicono correttamente che è perché XOR richiede due argomenti, IMO le risposte sopra non sembrano spiegare sufficientemente PERCHÉ XOR ha effettivamente bisogno di due argomenti. Ovviamente ti senti diversamente, ma per me era evidente dai vari commenti su questa pagina che la doppia argomentazione di base di XOR non era stata ancora completamente spiegata a un principiante assoluto.
Kevin Holt

1
Mi hai convinto.
15ee8f99-57ff-4f92-890c-b56153

@Kevin Holt - Logical XOR è significativo se hai bisogno che una delle condizioni sia vera ma non entrambe. Che devi valutare entrambe le condizioni non importa. Il problema del cortocircuito è un dettaglio di basso livello di cui ti devi preoccupare solo quando hai a che fare con codice critico per le prestazioni (il flusso di controllo è lento). Sarei più interessato a cosa si suppone significhi "esclusivo o" quando ne ricava un operatore logico. Vale a dire, fallo funzionare come la versione bit per bit (come gli altri operatori), o rendilo un o esclusivo (tutte le condizioni che vuoi, ma solo una può essere vera).
Thorham

-3

Questa domanda ha avuto una risposta affettuosa, ma mi sono imbattuto in una situazione diversa. È vero che non è necessario uno XOR condizionale. È anche vero che può essere utilizzato l'operatore ^. Tuttavia, se è necessario testare solo lo stato "true || false" degli operandi, ^ può causare problemi. Per esempio:

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 questo esempio, se sinistra è impostata su 10 (0xa) e destra è impostata su 5 (0x5), viene immesso il ramo "riuscito". Per questo esempio (semplicistico anche se sciocco), ciò comporterebbe un bug poiché non dovresti girare a sinistra E a destra allo stesso tempo. Ciò che ho raccolto dall'interrogante non è che in realtà volesse un condizionale, ma un modo semplice per eseguire il vero / falso sui valori passati a xor.

Una macro potrebbe fare il trucco:

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

Sentiti libero di prendermi a schiaffi se non sono nel segno: o)

Ho letto la risposta di jimreed di seguito dopo aver pubblicato questo (cattivo Yapdog!) E la sua è in realtà più semplice. Funzionerebbe e non ho assolutamente idea del motivo per cui la sua risposta è stata respinta ...


3
Questa è una domanda in C #, non in C / C ++. ifrichiede un'espressione booleana, non verrà nemmeno compilato con un int.
Marc L.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.