Условный XOR?

87

Почему в C # нет условного XORоператора?

Пример:

true  xor false = true
true  xor true  = false
false xor false = false
Гилад Нааман
источник
15
Как !=работает заменитель?
Pascal Cuoq
45
C # делает иметь XOR оператор (х ^ у). Поэтому я отрицаю предпосылку вопроса. Можете ли вы объяснить, почему вы считали, что в C # нет оператора xor? Мне интересно узнать, почему люди верят в ложь о C #.
Эрик Липперт
3
@ Эрик Липперт: Я думаю, он имеет в виду логические операторы ( & | ^) и условные операторы ( && ||). Но вы правы (конечно), есть логичный XOR ...
BoltClock
14
@BoltClock: О, если возникает вопрос «почему нет короткозамкнутого оператора xor?» - как могло быть? С «и», если первый аргумент ложен, вам не нужно оценивать второй. С «или», если первый аргумент истинен, то второй оценивать не нужно. Вам всегда нужно оценивать оба аргумента для xor, поэтому короткое замыкание невозможно.
Эрик Липперт
4
Сам вопрос лучше подходит для Microsoft - и это достойная причина для отрицательного голоса - но если тот, кто проголосовал против, сделал это из-за оператора ^, то вам нужно прочитать с большим вниманием к деталям, потому что вопрос был условным, а не логично, а не просто «почему нет XOR».
The Evil Greebo

Ответы:

121

В C # условные операторы выполняют свой вторичный операнд только при необходимости .

Поскольку XOR по определению должен проверять оба значения, условная версия была бы глупой.

Примеры :

  • Логическое И: &- каждый раз проверяет обе стороны.

  • Логическое ИЛИ: |- каждый раз проверяйте обе стороны.

  • Условное И: &&- проверяет только 2-ю сторону, если 1-я сторона истинна.

  • Условное ИЛИ: ||- проверять только вторую сторону, если первая сторона ложна.

Злой Грибо
источник
35
Оператор XOR не нарушит соглашение «условные операторы выполняют свой вторичный операнд только в случае необходимости». Это всегда было бы необходимо.
Натан Ковнер
2
Условный XOR может быть красивым и элегантным ярлыком для некоторых конкретных шаблонов, хотя не уверен, достаточно ли оправдан, чтобы включить его в язык. Примером таких шаблонов, в которых может оказаться полезным XOR, является условное отрицание: когда логическое выражение должно быть инвертировано или нет, учитывая второе логическое выражение.
SalvadorGomez
1
Некоторое время я не отвечал на это, но отвечу на популярный комментарий @KhyadHalda: зачем вам когда-либо создавать то, что, как вы знаете, никогда не будет использоваться? Вы бы намеренно написали мертвый код.
The Evil Greebo
Учитывая, что условный оператор XOR не нарушает определенное вами соглашение (комментарий Хьяда), в сочетании с тем фактом, что он действительно может быть полезен в некоторых случаях, он в значительной степени сводит на нет любую «глупость», которую вы приписываете существованию такого оператора.
Syndog
1
Как вообще может быть полезен условный XOR? Условное исключающее ИЛИ никогда не может быть оценено без сравнения обеих сторон, чтобы определить, равны они или нет. Даже понятие условного XOR, сравнивающего два bool, должно по-прежнему проверять значение каждого bool и проверять равенство.
The Evil Greebo
280

Вопрос немного устарел, но ...

Вот как должен работать этот оператор:

true xor false = true
true xor true = false
false xor true = true
false xor false = false

Вот как оператор! = Работает с типами bool:

(true != false) // true
(true != true) // false
(false != true) // true
(false != false) // false

Как видите, несуществующие ^^можно заменить существующими!=

пиотрпо
источник
46
На самом деле это единственный ответ, который прямо и правильно решает вопрос.
usr
39
Я сижу здесь и жалую себя, что не понимал, !=что это сработает.
AdamMc331
1
Ответ правильный, но нет комментариев. Он не отвечает на вопрос «почему в C # нет условного XOR?». Строго говоря, это не логический оператор, это оператор относительного равенства. Хотя результат такой же, как XOR, он находится в другом классе. Он сравнивается с XOR только при тестировании двух логических значений, и обе стороны оператора по-прежнему должны оцениваться.
The Evil Greebo
3
@TheEvilGreebo - То, что вы говорите, правда; Оператор! = технически не является условным оператором XOR. Однако этот ответ фактически говорит: «Условный оператор XOR не существует, потому что существует оператор! =». Во всяком случае, я так это читаю.
Syndog
6
Я думаю, что почти все, кто дошел до этого поста, действительно хотели написать XOR для логических значений. как есть логическое ANDи , ORно ничего , какXOR . или, по крайней мере, мы не осознавали !=:) @TheEvilGreebo
М.казем Ахгары
30

Есть логический оператор XOR: ^

Документация: операторы C # и оператор ^

Iceaway
источник
2
Логично, а не условно. Логическое и = &, условное и = &&. Он спрашивает об условном.
The Evil Greebo
3
Это бинарно, а не логично. Предполагается, что bools равны 0 или 1, что неверно в среде CLR.
usr
1
извините, этот ответ на самом деле не отвечает на вопрос об УСЛОВНЫХ операторах. это немного оператор
Натан Трегиллус
2
Для записи в документации, указанной в этом ответе, явно указано, что ^при использовании с логическими операндами это логический оператор. "для операндов типа bool оператор ^ вычисляет тот же результат, что и оператор неравенства! =". Вы также можете выполнить побитовое xor целочисленные операнды с помощью ^. C # - это не C.
15ee8f99-57ff-4f92-890c-b56153
24

В качестве пояснения, оператор ^ работает как с целочисленными типами, так и с bool.

См . Оператор ^ MSDN (Справочник по C #) :

Двоичные операторы ^ предопределены для целочисленных типов и bool. Для целочисленных типов ^ вычисляет побитовое исключающее ИЛИ своих операндов. Для операндов типа bool ^ вычисляет логическое исключающее ИЛИ своих операндов; то есть результат будет истинным тогда и только тогда, когда истинен ровно один из его операндов.

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

РичардCL
источник
2
давно занимаюсь программированием на C #, никогда этого не знал! спасибо @RichardCL!
Натан Трегиллус
Это хорошая информация, но кажется более подходящей в качестве комментария или редактирования другого ответа, который упоминается ^и предшествует этому на пять лет. Я сомневаюсь, что что-то изменилось.
Крис
13

Как спросил Марк Л. Вот правильная версия:

 Func<bool, bool, bool> XOR = (X,Y) => ((!X) && Y) || (X && (!Y));

Вот таблица истинности:

 X | Y | Result
 ==============
 0 | 0 | 0
 1 | 0 | 1
 0 | 1 | 1
 1 | 1 | 0

Ссылка: Эксклюзивное ИЛИ

Простой товарищ
источник
2
Был задан вопрос: ПОЧЕМУ в C # нет условного оператора XOR. Это не отвечает на вопрос. Что касается самой функции: эта функция действительно работает как условное XOR - однако вопрос в том, эффективнее ли она, чем безусловное XOR? Чтобы проверить исключительную истинность, XOR должен подтвердить, что истинен один и ровно один результат. Это означает, что необходимо оценивать и сравнивать обе стороны. Вышеупомянутая функция проверяет обе стороны условия и, инвертируя как минимум одно значение. Знаем ли мы изнутри, отличается ли это от XOR?
Злой Грибо
6

О да, это так.

bool b1 = true;
bool b2 = false;
bool XOR = b1 ^ b2;
Армен Цирунян
источник
1
Это бинарный оператор, а не логический. Предполагается, что bools равны 0 или 1, что неверно в среде CLR. Так что этот код может действительно не работать.
usr
6
@usr, В C # оператор ^ логичен при применении к двум логическим операндам. Вы очень много прокомментировали эти ответы, запускали ли вы когда-нибудь код для проверки своей гипотезы?
Marc L.
2
@MarcL. Я сделал: pastebin.com/U7vqpn6G Выводит истину, хотя истина ^ истина предполагается ложной. bool не всегда равно 0 или 1. Это не логический тип в среде CLR. Это 8-битная величина с произвольным содержимым. Я мог бы создать проверяемый IL, чтобы продемонстрировать проблему.
usr
2
Например, при использовании других языков CLR, кроме C #. Повторяю: я мог бы использовать ILASM для создания полностью проверяемой и безопасной сборки, которая делает это (на уровне IL логическое значение - это i1просто, как и байт). Это 100% определенное и безопасное управляемое поведение. CLR не является грубым; Впервые я увидел такое поведение при использовании Microsoft Pex.
usr
1
@EdPlunkett, я не думаю, что твой грузовик со мной. usr показал, что внутренне это фактически бинарный оператор. «Жестокое обращение», на которое я жаловался, было средством, с помощью которого он это доказал, что я все еще считаю слишком резким. Это может случиться, но использование Boolean настолько тщательно, что использование его в качестве CLR-безопасного было бы в лучшем случае опасным, а в худшем - оскорбительным (если не злонамеренным) и должно рассматриваться как ошибка. Usr доказывает, что C # внутренне больше похож на C, чем мы думали. Другой вопрос, следует ли считать код, который это делает, действительным.
Марк Л.
4

Условного xor не существует, но вы можете использовать логический, потому что xor определен для логических значений, и все условные сравнения оцениваются как логические.

Итак, вы можете сказать что-то вроде:

if ( (a == b) ^ (c == d))
{

}
Кларк
источник
Это бинарный оператор, а не логический. Предполагается, что bools равны 0 или 1, что неверно в среде CLR. Так что этот код может действительно не работать.
usr
@usr что значит CLR? Это сработало для меня, не уверен, что я пропустил здесь
крайний
3
@Spencevail, вероятно, вы не думали о том, что логическое значение, не являющееся ложным, может не иметь целочисленного представления 1. Это малоизвестный факт. Вы можете оказаться в ситуации, когда xor двух логических значений, не являющихся ложными, по-прежнему не является ложным! Тем не менее, в этом конкретном коде оператор xor применяется только к значениям в [0,1], поэтому мой комментарий не применяется (полностью).
usr
1
@Spencevail это именно тот случай, который может потерпеть неудачу. Можно создать безопасную функцию управляемого кода CreateBool (byte), которая преобразует байт в логическое число тех же битов. Тогда CreateBool (1) ^ CreateBool (2) истинно, но CreateBool (1) истинно, и CreateBool (2) также истинно! &также уязвим.
usr
1
На самом деле, я только что сообщил об ошибке RyuJIT, потому что они не учли эту возможность и скомпилировали так, &&как если бы это была &неправильная компиляция.
usr
3

Хотя существует логический оператор xor ^, нет условного оператора xor. Вы можете добиться условного xor двух значений A и B, используя следующее:

A ? (!B) : B

Парены не обязательны, но я добавил их для ясности.

Как указывает The Evil Greebo, это оценивает оба выражения, но xor не может быть сокращено, как and and or .

Джимрид
источник
В чем разница между логическим ^ и условным ^? oO
Армен Цирунян
@Armen Tsirunyan Логические операторы выполняют побитовые операции в типах, где это имеет смысл, в то время как условные операторы работают с логическими значениями и возвращают логический результат. Учитывая логические значения: 0101 ^ 0011имеет значение 0110.
jimreed
3
нет, вы совершенно не правы. в C # есть оба типа XOR (они называются поразрядным и логическим соответственно). Оба используют символ ^.
Армен Цирунян
1

ты можешь использовать:

a = b ^ c;

как в c / c ++

гулян
источник
0

Не существует такой вещи, как условное (короткое замыкание) XOR. Условные операторы имеют смысл только тогда, когда есть способ окончательно определить окончательный результат, глядя только на первый аргумент. Для XOR (и сложения) всегда требуется два аргумента, поэтому после первого аргумента невозможно выполнить короткое замыкание.

Если вы знаете, что A = true, тогда (A XOR B) =! B.

Если вы знаете, что A = false, тогда (A XOR B) = B.

В обоих случаях, если вы знаете A, но не B, то вы знаете недостаточно (A XOR B). Вы всегда должны запоминать значения как A, так и B, чтобы вычислить ответ. Буквально не существует варианта использования, при котором вы когда-либо могли бы разрешить XOR без обоих значений.

Имейте в виду, что XOR по определению имеет четыре случая:

false xor true  = true
true  xor false = true
true  xor true  = false
false xor false = false

Опять же, надеюсь, из вышеизложенного очевидно, что знания первого значения никогда не достаточно, чтобы получить ответ, не зная второго значения. Однако в своем вопросе вы пропустили первый случай. Если бы вы вместо этого хотели

false op true  = false (or DontCare)
true  op false = true
true  op true  = false
false op false = false

то вы действительно можете получить это с помощью условной операции короткого замыкания:

A && !B

Но это не XOR.

Кевин Холт
источник
Я не вижу в этом ответе ничего, чего нет хотя бы в одном ответе выше. Я не вижу никаких указаний на то, что ваш закорачиваемый un-xor - это то, что искал OP, поскольку он принял ответ, который предполагает, что ему нужен правильный xor.
15ee8f99-57ff-4f92-890c-b56153
Мой - буквально единственный предложенный до сих пор ответ, который может создать запрашиваемую OP таблицу истинности без оценки второго аргумента.
Кевин Холт
Также OP спросил, почему нет условного XOR, и хотя приведенные выше ответы правильно говорят, что это потому, что XOR требует двух аргументов, IMO ответы выше, похоже, не достаточно объясняют, ПОЧЕМУ XOR действительно требует два аргумента. Очевидно, вы считаете иначе, но мне было очевидно из различных комментариев на этой странице, что базовая двухаргументность XOR еще не была полностью объяснена новичку.
Кевин Холт
1
Вы меня уговорили.
15ee8f99-57ff-4f92-890c-b56153
@Kevin Holt - логический XOR имеет смысл, если вам нужно, чтобы одно из условий было истинным, но не оба. То, что вы должны оценить оба условия, не имеет значения. Короткое замыкание - это мелочь на низком уровне, о которой вам нужно беспокоиться только при работе с критически важным для производительности кодом (поток управления медленный). Я был бы больше озабочен тем, что должно означать «исключающее или» при создании из него логического оператора. А именно, пусть он работает как побитовая версия (как и другие операторы), или делает его исключительным (сколько угодно условий, но только одно может быть истинным).
Торхэм
-3

На этот вопрос был дан эмоциональный ответ, но я столкнулся с другой ситуацией. Это правда, что в условном XOR нет необходимости. Также верно, что можно использовать оператор ^. Однако, если вам нужно только проверить состояние операндов «истина || ложь», то ^ может привести к проблемам. Например:

void Turn(int left, int right)
{
    if (left ^ right)
    {
        //success... turn the car left or right...
    }
    else
    {
        //error... no turn or both left AND right are set...
    }
}

В этом примере, если для left установлено значение 10 (0xa), а для right установлено значение 5 (0x5), выполняется переход «успешно». Для этого (упрощенного, хотя и глупого) примера это приведет к ошибке, так как вы не должны одновременно поворачивать налево и направо. Я понял от спрашивающего не то, что он действительно хотел условное, а простой способ выполнить истинное / ложное для значений, переданных в xor.

Макрос может помочь:

#define my_xor(a, b) ( ((a)?1:0) ^ ((b)?1:0) )

Не стесняйтесь шлепать меня, если я ошибаюсь: o)

Я прочитал ответ Джимрида ниже после того, как опубликовал это (плохой Yapdog!), И его на самом деле проще. Это сработает, и я абсолютно не понимаю, почему его ответ был отклонен ...

Яп Собака
источник
3
Это вопрос C #, а не C / C ++. ifтребует логического выражения, оно даже не будет компилироваться с int.
Marc L.