2010-08-12 12 views
28

Was ist der einfachste Weg, um ein dreiseitiges exklusives ODER zu machen?XOR von drei Werten

Mit anderen Worten, ich habe drei Werte, und ich möchte eine Aussage, die zu wahren IFF nur ein der drei Werte ist wahr ist.

Bisher ist es das, was ich habe kommen mit:

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

Gibt es etwas einfacher, das Gleiche zu tun?


Hier ist der Beweis dafür, dass die obige Aufgabe erfüllt:

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 

Antwort

34

Für genau drei Begriffe, können Sie diesen Ausdruck verwenden:

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

Der erste Teil ist true iff ein oder drei der Begriffe sind true. Der zweite Teil des Ausdrucks stellt sicher, dass nicht alle drei true sind.

Beachten Sie, dass der obige Ausdruck nicht verallgemeinern zu mehr Begriffe. Eine allgemeine Lösung ist, um tatsächlich Zählung wie viele Begriffe true sind, so etwas wie dieses:

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

groß, aber die allgemeine Lösung nicht kurzschließen. – Ani

+0

'a? 1: 0' kann vereinfacht werden zu '!! a' – kaspersky

+0

@ gg.kaspersky, nur in JavaScript, C, und Sprachen, die truthy/falsy-Tests über den '!' - Operator haben. Zum Beispiel würde dies in Java oder C# nicht funktionieren. –

9

a^b^c ist nur 1, wenn eine ungerade Anzahl von Variablen ist 1 (zwei ‚1‘ würde sich gegenseitig aufheben). Sie müssen also nur für den Fall prüfen, „alle drei sind 1“:

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

Ich liebe es. Sehr einfach und verständlich. –

+0

Die einfachste und muss verständlich beim Lesen des Codes (Nun, ich würde einige Leerzeichen hinzufügen) – gerardw

5

Eine andere Möglichkeit:

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

die 9 Zeichen kürzer als das passiert zu sein akzeptierte Antwort :)

1

Hier ist eine allgemeine Implementierung, die schnell scheitert, wenn mehr als eine bool ist true.

Nutzungs:

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

Weil ich kann.

2

Sie könnten auch versuchen (in C):

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

+0

Dies ist nur in einigen Sprachen [z. Javascript], und es ist keine Vereinfachung. In einer Sprache, die den booleschen Wert für '+' in Zahl umwandelt, wenn 'a',' b' und 'c' bereits boolesch sind, brauchen Sie auch nicht die doppelte Negation' !! ': nur' a + b + c === 1 wird gleichwertig sein. – blgt

+1

@blgt, mein Fehler, ich sollte angeben, dass ich eine Antwort für C-Sprache sein wollte. – kaspersky

+0

'' 'zu verwenden, um ein C zu garantieren ist wahr' 1 'ist wirklich ziemlich ordentlich. Ein bisschen paranoid im Kontext einer booleschen logischen Frage. Wenn der Rest Ihres Codes gut geschrieben ist, sollte a + b + c == 1 noch ausreichend sein – blgt