2010-08-12 41 views
28

Quelle est la manière la plus simple de faire un OR exclusif à trois voies? En d'autres termes, j'ai trois valeurs, et je veux une déclaration qui évalue à vrai IFF seulement un des trois valeurs est vrai.XOR de trois valeurs

Jusqu'à présent, ce que je suis venu avec:

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

Y at-il quelque chose de simple à faire la même chose?


est ici la preuve que le ci.dessus fait:

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 

Répondre

34

Pour exactement trois termes, vous pouvez utiliser cette expression:

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

La première partie est true ssi un ou trois des termes sont true. La deuxième partie de l'expression garantit que tous les trois ne sont pas true.

Notez que l'expression ci-dessus ne pas généraliser à plus de termes. Une solution plus générale est en fait nombre combien de termes sont true, donc quelque chose comme ceci:

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

Grand, mais la solution générale ne fait pas de court-circuit. – Ani

+0

'a? 1: 0' peut être simplifié à '!! a' – kaspersky

+0

@ gg.kaspersky, seulement en JavaScript, C, et les langages qui ont des tests de vérité/fausseté via l'opérateur'! '. Par exemple, cela ne fonctionnerait pas en Java ou C#. –

9

a^b^c est seulement 1 si un nombre impair de variables est de 1 (deux « 1 » annulerait les uns les autres). Donc, il vous suffit de vérifier le cas « tous les trois sont 1 »:

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

Je l'aime. Très simple et compréhensible. –

+0

Le plus simple et doit comprendre en lisant le code (bien, je ajouterais quelques espaces) – gerardw

5

Une autre possibilité:

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

qui se trouve être 9 caractères plus courte que la réponse acceptée :)

1

Voici une implémentation générale qui échoue rapidement lorsque plus d'un bool s'avère être true.

Utilisation:

XOR(a, b, c); 

code:

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

Parce que je peux.

2

Vous pouvez également essayer (en C):

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

+0

Ceci est uniquement valable dans certaines langues [par ex. javascript], et ce n'est pas une simplification. Dans un langage qui convertit automatiquement booléen en nombre pour '+ ', si' a', 'b' et' c' sont déjà booléens, vous n'avez pas non plus besoin de la double négation '!!': juste 'a + b + c === 1' sera équivalent. – blgt

+1

@blgt, mon erreur, je devrais préciser que je voulais être une réponse pour le langage C. – kaspersky

+0

En utilisant '!!' pour garantir un C true, '1' est en fait assez soigné. Un peu paranoïaque dans le contexte d'une question de logique booléenne. Si le reste de votre code est bien écrit 'a + b + c == 1' devrait toujours être suffisant – blgt