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

7 ответов


для ровно трех терминов вы можете использовать следующее выражение:

(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

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

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

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

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

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

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


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

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


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

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

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