Подтвердить что ты не робот

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

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

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

До сих пор это то, что я придумал:

((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
4b9b3361

Ответ 1

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

(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

Ответ 2

bool result = (a?1:0)+(b?1:0)+(c?1:0) == 1;

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

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

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

Ответ 6

Здесь общая реализация, которая быстро выходит из строя, когда найдено более чем 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;
}

Ответ 7

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

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

Ответ 8

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

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

Это также может быть использовано в операторах if!

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