2010-08-12 15 views
28

Qual è il modo più semplice per eseguire un OR esclusivo a tre vie?XOR di tre valori

In altre parole, ho tre valori e desidero una dichiarazione che valuti solo il vero IFF uno dei tre valori è vero uno.

Finora, questo è quello che è venuta in mente:

(! (A^b) & & (a^c) & & (b & & c)) || ((b^a) & & (b^c) & &! (a & & c)) || ((C^a) & & (c^b) & &! (Un & & b))

C'è qualcosa di più semplice per fare la stessa cosa?


ecco la prova che quanto sopra compie il compito:

a = true; b = true; c = true 
((a^b) && (a^c) && !(b && c)) || ((b^a) && (b^c) && !(a && c)) || ((c^a) && (c^b) && !(a && b)) 
=> false 

a = true; b = true; c = false 
((a^b) && (a^c) && !(b && c)) || ((b^a) && (b^c) && !(a && c)) || ((c^a) && (c^b) && !(a && b)) 
=> false 

a = true; b = false; c = true 
((a^b) && (a^c) && !(b && c)) || ((b^a) && (b^c) && !(a && c)) || ((c^a) && (c^b) && !(a && b)) 
=> false 

a = true; b = false; c = false 
((a^b) && (a^c) && !(b && c)) || ((b^a) && (b^c) && !(a && c)) || ((c^a) && (c^b) && !(a && b)) 
=> true 

a = false; b = true; c = true 
((a^b) && (a^c) && !(b && c)) || ((b^a) && (b^c) && !(a && c)) || ((c^a) && (c^b) && !(a && b)) 
=> false 

a = false; b = true; c = false 
((a^b) && (a^c) && !(b && c)) || ((b^a) && (b^c) && !(a && c)) || ((c^a) && (c^b) && !(a && b)) 
=> true 

a = false; b = false; c = true 
((a^b) && (a^c) && !(b && c)) || ((b^a) && (b^c) && !(a && c)) || ((c^a) && (c^b) && !(a && b)) 
=> true 

a = false; b = false; c = false 
((a^b) && (a^c) && !(b && c)) || ((b^a) && (b^c) && !(a && c)) || ((c^a) && (c^b) && !(a && b)) 
=> false 

risposta

34

Per esattamente tre termini, è possibile usare questa espressione:

(a^b^c) && !(a && b && c) 

La prima parte è true se e solo se uno o tre dei termini sono true. La seconda parte dell'espressione assicura che non tutti e tre sono true.

Si noti che l'espressione di cui sopra fa NON generalizza a più termini. Una soluzione più generale è quello di realtà conteggio quanti termini sono true, quindi qualcosa di simile:

int trueCount = 
    (a ? 1 : 0) + 
    (b ? 1 : 0) + 
    (c ? 1 : 0) + 
    ... // more terms as necessary 

return (trueCount == 1); // or some range check expression etc 
+0

Grande, ma la soluzione generale non lo fa corto circuito. – Ani

+0

'a? 1: 0' può essere semplificato in '!! a' – kaspersky

+0

@ gg.kaspersky, solo in JavaScript, C e lingue che hanno test di verità/falsità tramite l'operatore'! '. Ad esempio, questo non funzionerebbe in Java o C#. –

9

a^b^c è 1 solo se un numero dispari di variabili è 1 (due '1' avrebbe annullare a vicenda). Quindi non vi resta che verificare il caso "tutti e tre sono 1":

result = (a^b^c) && !(a&&b&&c) 
9
bool result = (a?1:0)+(b?1:0)+(c?1:0) == 1; 
+1

Mi piace. Molto semplice e comprensibile. –

+0

Il più semplice e deve essere comprensibile durante la lettura del codice (beh, vorrei aggiungere alcuni spazi) – gerardw

5

Altra possibilità:

a ? !b && !c : b^c 

che risulta essere 9 caratteri più corta della risposta accettata :)

1

Ecco un'implementazione generale che non riesce rapidamente quando più di uno bool è risultato essere true.

Uso:

XOR(a, b, c); 

Codice:

public static bool XOR(params bool[] bools) 
{ 
    return bools.Where(b => b).AssertCount(1); 
} 

public static bool AssertCount<T>(this IEnumerable<T> source, int countToAssert) 
{ 
    int count = 0; 
    foreach (var t in source) 
    { 
     if (++count > countToAssert) return false; 
    } 

    return count == countToAssert; 
} 
1
f= lambda{ |a| [false, false, true].permutation.to_a.uniq.include? a } 
p f.call([false, true, false]) 
p f.call([false, true, true]) 

$ true

$ false

Perché posso.

2

Si potrebbe anche provare (in C):

!!a + !!b + !!c == 1

+0

Questo è valido solo in alcune lingue [ad es. javascript], e non è una semplificazione. In una lingua che converte automaticamente il numero booleano in '+', se 'a',' b' e 'c' sono già booleani, non è necessaria la doppia negazione' !! ': just' a + b + c === 1' sarà equivalente. – blgt

+1

@blgt, errore mio, dovrei specificare che intendevo essere una risposta per il linguaggio C. – kaspersky

+0

L'uso di '!!' per garantire una C true è '1' in realtà è abbastanza accurato. Un po 'paranoico nel contesto di una domanda logica booleana. Se il resto del codice è ben scritto, 'a + b + c == 1' dovrebbe essere ancora sufficiente – blgt

Problemi correlati