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

Xor с 3 значениями

Мне нужно сделать xor условным между 3 значениями, т.е. мне нужно, чтобы одно из трех значений было истинным, но не более одного, а не none.

Я думал, что могу использовать оператор xor ^ для этого, но он не работает должным образом.

Я ожидал, что это вернет false, но это не так. (true ^ true ^ true)

все другие комбинации, похоже, работают так, как я ожидал.

При просмотре документов для оператора xor они говорят только о сравнении двух значений, и я не могу найти что-либо в этом случае для трех или более значений в Интернете.

Может ли кто-нибудь пролить свет или предложить простой способ сделать это?

4b9b3361

Ответ 1

((true ^ true) ^ true) вернет true, чего вы не ожидаете от true ^ true ^ true.

Чтобы убедиться, что вы получите желаемый результат (только одно значение будет истинным), выполните следующие действия:

if ((a && !b && !c) || (!a && b && !c) || (!a && !b && c))

В качестве альтернативы, исходя из ответа @jcomeau_ictx, вы можете сделать следующее:

if( Convert.ToInt32(a) + Convert.ToInt32(b) + Convert.ToInt32(c) == 1 )

Или вы можете создать функцию:

public bool TernaryXor(bool a, bool b, bool c)
{
    //return ((a && !b && !c) || (!a && b && !c) || (!a && !b && c));

    // taking into account Jim Mischel comment, a faster solution would be:
    return (!a && (b ^ c)) || (a && !(b || c));
}

EDIT: вы можете назвать функцию TernaryXor так, чтобы она была более понятной в отношении результата функции.

Ответ 3

Поскольку я не могу получить достаточно Linq, как насчет:

new[] { a, b, c }.Count(v => v) == 1

Ответ 4

Это сложно, конечно. Учитывая то, что вы хотите:

a b c rslt
0 0 0  0
0 0 1  1
0 1 0  1
0 1 1  0
1 0 0  1
1 0 1  0
1 1 0  0
1 1 1  0

Это будет сделано:

rslt = (!a & (b ^ c)) || (a & !(b | c));

Первая часть обрабатывает четыре случая, когда a равно 0. Вторая часть, где a не равна 0.

Более простой способ взглянуть на это:

rslt = (a | b | c) & !((a & b) | (a & c) | (b & c))

То есть, одно из трех должно быть истинным, но не может быть двух (или более).

Кажется, должен быть способ упростить дальше, но это не приходит в голову. Может быть, мне нужно больше кофеина.

ИЗМЕНИТЬ

Я думаю, что это решение, которое я искал сегодня утром:

rslt = a ? !(b | c) : (b ^ c);

Теперь, почему я использовал | вместо ||:

Это комбинация проблемы стиля и старого уклона против ветвления (старые привычки умирают тяжело). !(b | c) генерирует этот код IL:

ldarg.1
ldarg.2
or
ldc.i4.0
ceq
stloc.0

В этом коде нет ветвей. Если я использую ||, как в !(b ||c), он генерирует:

  ldarg.1
  brfalse.s IL_009B
  ldarg.2
  br.s IL_009C
IL_009B:
  ldc.i4.1
IL_009C:
  stloc.0

Которая имеет две ветки. Я не знаю, отразится ли код JIT, но я подозреваю, что это произойдет. Таким образом, один бит кода - это 6 команд, которые всегда выполняются. Другой - 6 инструкций, из которых иногда исполняется только 4. Но разветвляющиеся штрафы могут очень хорошо поглощать любые выгоды от выполнения двух инструкций.

Я понимаю, что современные процессоры намного лучше разветвляются, чем 8086, и, возможно, не будет заметной разницы во времени выполнения этих двух фрагментов кода. Даже если бы это было так, маловероятно, что это существенно повлияет на общую продолжительность программ, которые я обычно пишу.

Но я говорю вам, что он, безусловно, привык! На 8086, где ветвление было очень дорого, разница между (b | c) и (b || c) была огромной.

Наконец, используя |, как вы заметили, принудительно оценивает все выражение. Мой исходный код говорит, по сути, "если это выражение истинно или что выражение истинно". Использование && и || превращает его в кучу условностей и в моем мозгу труднее читать.

Итак: старый предрассудок, основанный на наиболее вероятных устаревших соображениях производительности. Но безвредно.

Однако нужно быть осторожным, чтобы не писать что-то вроде (b() | c()), если обе функции не должны оцениваться.

Ответ 5

это коротко! (a & b & c) && (А ^ Ь ^ с)

Ответ 6

XOR является двоичным оператором, его можно использовать только по 2 значениям за раз. Поэтому, когда вы выполняете (true XOR true XOR true), на самом деле это делает ((true XOR true) XOR true)...

Внутренний (true XOR true) разрешает false, потому что они одинаковы. С этим решением остаток (false XOR true), который разрешает true.

Похоже, вы пытаетесь быть умными или суперэффективными в соответствии с вашими условиями. Это, вероятно, займет несколько минут, чтобы разобраться, а затем написать таблицу истинности или тест, чтобы убедиться, что он правильно рассматривает все возможные комбинации.

Намного проще просто подсчитать, сколько из них true и сделать if (countTrues == 1). Причина этого в том, что у нее нет существенных накладных расходов, и она на самом деле понятна и понятна по сравнению с решением, использующим только бит-twiddling (здесь есть еще несколько ответов, которые демонстрируют это).

Ответ 7

Используя XOR, if (false^false^false) должен вернуться false. Он работает, как XOR supposted для работы. Exclusive or возвращает true, если один и только один из элементов является истинным. Если все они ложные, они вернут false.

Если вы хотите сделать это с 3 значениями, скажем a, b и c, выражение должно выглядеть примерно так: (a или b или c) и ~ (a и b) и ~ (a и c) и ~ (b и c)

более правильный формат: (a v b v c) * ~ (a * b) * ~ (a * c) * ~ (b * c)

Ответ 8

XOR является двоичным оператором и не работает на более чем двух операндах. Учитывая порядок операций, когда вы смотрите: (false ^ false ^ false), вы действительно получаете `((false ^ false) ^ false).

Принимая это в виду, с точки зрения оценки того, будет ли это работать для вас, может быть полезно создать таблицу истинности для желаемой операции. В случае приведенного выше примера вы смотрите:

(Op1 XOR Op2) XOR Op3 = Result    
 F       F        F     F
 F       F        T     T 
 F       T        F     T 
 F       T        T     F
 T       F        F     T
 T       F        T     F
 T       T        F     F
 T       T        T     T

Что делает XOR проблемой в случае, когда все операнды истинны и могут потребоваться некоторые специальные действия, скажем, добавив AND not (Op1 AND Op2 AND Op3).

Ответ 9

Пришел к этому, пока я пошел по неправильному пути, пытаясь решить мою собственную проблему (XOR по 4 значениям); решил, что LINQ - это самый простой способ справиться с этой проблемой для N-случая;

bool OneAndOnlyOneIsTrue(IEnumerable<bool> conditions)
{
    return conditions.Count(c => c) == 1;
}

Вызывается как:

bool OneLuckyGuy(Person p1, Person p2, Person p3, Person p4)
{
     return OneAndOnlyOneIsTrue(new [] {         
         p1.IsAMan(),
         p2.IsAMan(),
         p3.IsAMan(),
         p4.IsAMan()
     });
}

По инструкциям, это проверяет каждое условие один раз, поэтому функция O (n), но она гибкая и проклятый сайт более читабельен, чем побитовая альтернатива.; -)

Ответ 10

простое решение

a = true; b = false; c = true

(a ^ b) || (a ^ c)