XOR трех значений - PullRequest
       43

XOR трех значений

34 голосов
/ 12 августа 2010

Какой самый простой способ сделать трехстороннее эксклюзивное ИЛИ?

Другими словами, у меня есть три значения, и я хочу получить утверждение, которое оценивается как истинное IFF * одно из трех значений является истинным.

Пока что вот что я придумал:

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

Есть ли что-то более простое, чтобы сделать то же самое?


Вот доказательство того, что вышеуказанное решает задачу:

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

Ответы [ 8 ]

41 голосов
/ 12 августа 2010

Точно три термина вы можете использовать это выражение:

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

Первая часть true, если один или три из терминов true.Вторая часть выражения гарантирует, что не все три являются true.

. Обратите внимание, что вышеприведенное выражение НЕ обобщает на несколько терминов.Более общее решение состоит в том, чтобы на самом деле считать , сколько терминов составляет true, поэтому что-то вроде этого:

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

return (trueCount == 1); // or some range check expression etc
11 голосов
/ 12 августа 2010
bool result = (a?1:0)+(b?1:0)+(c?1:0) == 1;
9 голосов
/ 12 августа 2010

a^b^c - это только 1, если неравное количество переменных равно 1 (два «1» отменяют друг друга).Так что вам просто нужно проверить на случай "все три равны 1":

result = (a^b^c) && !(a&&b&&c)
5 голосов
/ 25 августа 2010

Другая возможность:

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

, что на 9 символов короче принятого ответа:)

2 голосов
/ 20 мая 2014

Вы также можете попробовать (в C):

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

1 голос
/ 22 ноября 2012
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

Потому что я могу.

1 голос
/ 28 августа 2010

Вот общая реализация, которая быстро завершается сбоем, когда более одного bool оказывается true.

Использование :

XOR(a, b, c);

Код :

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;
}
0 голосов
/ 20 мая 2019

Еще лучше на Python:

result = (1 if a else 0)+(1 if b else 0)+(1 if c else 0) == 1

Это можно использовать и для операторов if!

Это спасло мой день для взаимоисключающих аргументов CLI через Click (все ненавидят click)

...