XOR condicional?

87

Por que C # não tem um XORoperador condicional ?

Exemplo:

true  xor false = true
true  xor true  = false
false xor false = false
Gilad Naaman
fonte
15
Como !=funciona como substituto?
Pascal Cuoq
45
C # faz ter um operador XOR (x ^ y). Eu, portanto, nego a premissa da questão. Você pode explicar por que você acreditava que C # não tem um operador xor? Estou interessado em saber por que as pessoas acreditam em coisas falsas sobre C #.
Eric Lippert
3
@Eric Lippert: Acho que ele está se referindo a operadores lógicos ( & | ^) versus operadores condicionais ( && ||). Mas você está certo (é claro), há um XOR lógico ...
BoltClock
14
@BoltClock: Oh, se a pergunta for "por que não há curto-circuito no operador xor?" - como poderia haver? Com "e" se o primeiro argumento for falso, você não precisa avaliar o segundo. Com "ou", se o primeiro argumento for verdadeiro, você não precisa avaliar o segundo. Você sempre precisa avaliar ambos os argumentos para xor, portanto, não há curto-circuito possível.
Eric Lippert
4
A pergunta em si é mais adequada para a Microsoft - e esse é um motivo decente para downvote - mas se quem fez downvote fez isso por causa do operador ^, então você precisa ler com mais atenção aos detalhes, porque a questão era condicional vs. lógico, não simplesmente "por que não existe um XOR".
The Evil Greebo

Respostas:

121

Em C #, os operadores condicionais apenas executam seu operando secundário se necessário .

Visto que um XOR deve, por definição, testar ambos os valores, uma versão condicional seria boba.

Exemplos :

  • E lógico: &- testa ambos os lados sempre.

  • OR lógico: |- teste ambos os lados sempre.

  • E condicional: &&- testa apenas o 2º lado se o 1º lado for verdadeiro.

  • OU condicional: ||- teste apenas o 2º lado se o 1º lado for falso.

The Evil Greebo
fonte
35
Um operador XOR não violaria a convenção "operadores condicionais somente executam seu operando secundário se necessário". Seria sempre necessário.
Nathan Kovner
2
O XOR condicional pode ser um atalho bom e elegante para alguns padrões específicos, embora não tenha certeza se justificado o suficiente para incluí-lo na linguagem. Um exemplo de tais padrões em que XOR pode ser útil é a Negação Condicional: quando uma expressão booleana deve ser negada ou não, dada uma segunda expressão booleana.
SalvadorGomez
1
Faz algum tempo que não respondo a isso, mas sim ao comentário popular de @KhyadHalda: Por que você construiria algo que sabe que nunca seria usado? Você estaria escrevendo deliberadamente um código morto.
The Evil Greebo
Dado que um operador XOR condicional não violaria a convenção que você define (comentário de Khyad), juntamente com o fato de que seria realmente útil em alguns casos, ele praticamente nega qualquer "tolice" que você atribui a tal operador existente.
Syndog
1
Como, sempre, um XOR condicional seria útil? Um XOR condicional nunca pode avaliar sem comparar os dois lados para determinar se eles são ou não iguais. Mesmo a noção de um XOR condicional comparando dois bools ainda deve verificar o valor de cada bool e testar a igualdade.
The Evil Greebo
280

A pergunta está um pouco desatualizada, mas ...

É assim que esse operador deve funcionar:

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

É assim que o operador! = Funciona com tipos bool:

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

Como você vê, o inexistente ^^pode ser substituído pelo existente!=

piotrpo
fonte
46
Na verdade, esta é a única resposta que aborda a questão de maneira direta e correta.
usr
39
Estou sentado aqui, olhando para mim mesmo, que não sabia !=que funcionaria para isso.
AdamMc331
1
A resposta está correta, mas os comentários não. Ele não aborda a questão, que é "por que o C # não tem um XOR condicional?". Estritamente falando, este não é um operador lógico, é um operador de igualdade relacional. Embora o resultado seja o mesmo que XOR, ele está em uma classe diferente. Ele só se compara ao XOR ao testar dois valores booleanos, e ambos os lados do operador ainda devem ser avaliados.
The Evil Greebo
3
@TheEvilGreebo - O que você diz é verdade; o! = operador não é tecnicamente um operador XOR condicional. No entanto, essa resposta diz efetivamente: "Um operador XOR condicional não existe porque o operador! = Existe." É assim que eu li, de qualquer maneira.
Syndog de
6
Acho que quase todos que acabaram neste post realmente queriam escrever XOR sobre booleanos. como se houvesse lógico ANDe ORnada como XOR. ou pelo menos não percebemos !=:) @TheEvilGreebo
M.kazem Akhgary
30

Existe o operador lógico XOR: ^

Documentação: Operadores C # e Operador ^

fugir
fonte
2
Lógico, não condicional. Lógico e = &, condicional e = &&. Ele está perguntando sobre condicional.
The Evil Greebo
3
É binário, não lógico. Ele assume que os bools são 0 ou 1, o que não é verdadeiro no CLR.
usr
1
desculpe, esta resposta não responde realmente à pergunta sobre operadores CONDICIONAIS. isto é um pouco opperator
Nathan Tregillus
2
Para constar, a documentação vinculada a esta resposta afirma explicitamente que ^, quando usado com operandos booleanos, é um operador booleano. "para os operandos bool, o operador ^ calcula o mesmo resultado que o operador desigualdade! =". Você também pode bit a bit x ou operandos inteiros com ^. C # não é C.
15ee8f99-57ff-4f92-890c-b56153
24

Apenas para esclarecimento, o operador ^ funciona com tipos integrais e bool.

Consulte o Operador ^ do MSDN (referência C #) :

Operadores binários ^ são predefinidos para os tipos integrais e bool. Para tipos integrais, ^ calcula o OR exclusivo bit a bit de seus operandos. Para operandos bool, ^ calcula o exclusivo-or lógico de seus operandos; ou seja, o resultado é verdadeiro se e somente se exatamente um de seus operandos for verdadeiro.

Talvez a documentação tenha mudado desde 2011, quando essa pergunta foi feita.

RichardCL
fonte
2
programando em c # há muito tempo, nunca soube disso! obrigado @RichardCL!
Nathan Tregillus de
Esta é uma boa informação, mas parece mais apropriada como um comentário ou edição da outra resposta que menciona ^e antecede esta em cinco anos. Duvido que algo tenha mudado.
Chris
13

Conforme solicitado por Mark L , aqui está a versão correta:

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

Aqui está a tabela verdade:

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

Referência: OU exclusivo

Companheiro Simples
fonte
2
A pergunta feita foi POR QUE C # não tem um operador XOR condicional. Isso não responde à pergunta. Quanto à função em si: esta função opera como XOR condicional - no entanto, a questão é, é mais eficiente do que o XOR não condicional? Para testar a verdade exclusiva, XOR deve confirmar que um e exatamente um resultado é verdadeiro. Isso significa que ambos os lados devem ser avaliados e comparados. A função acima testa ambos os lados de uma condição e enquanto inverte um valor, no mínimo. Sabemos internamente se isso é diferente de XOR?
The Evil Greebo
6

Oh sim, é verdade.

bool b1 = true;
bool b2 = false;
bool XOR = b1 ^ b2;
Armen Tsirunyan
fonte
1
É um operador binário, não lógico. Ele assume que os bools são 0 ou 1, o que não é verdadeiro no CLR. Portanto, este código pode realmente não funcionar.
usr
6
@usr, em C #, o operador ^ é lógico quando aplicado a dois operandos booleanos. Você comentou muito com essas respostas, alguma vez executou algum código para testar sua hipótese?
Marc L.
2
@MarcL. Eu fiz: pastebin.com/U7vqpn6G Imprime verdadeiro, embora true ^ true deva ser falso. bool nem sempre é igual a 0 ou 1. Não é um tipo lógico no CLR. É uma quantidade de 8 bits com conteúdo arbitrário. Eu poderia ter gerado IL verificável para demonstrar o problema também.
usr
2
Ao usar outras linguagens CLR diferentes de C #, por exemplo. Repito: eu poderia ter usado o ILASM para criar um assembly totalmente verificável e seguro que fizesse isso (no nível de IL, um valor booleano é apenas um i1, assim como um byte). Este é um comportamento 100% definido e gerenciado de forma segura. O CLR não é maltratado .; A primeira vez que vi esse comportamento foi ao usar o Microsoft Pex.
usr
1
@EdPlunkett, acho que sua caminhonete não está comigo. usr mostrou que internamente é na verdade um operador binário . O "abuso" de que reclamei foi o meio pelo qual ele o provou, que ainda considero muito tenso. Pode acontecer, mas coloca o uso do Boolean tão completamente em terra de ninguém que implantá-lo como seguro para CLR seria perigoso na melhor das hipóteses, abusivo (se não malicioso) na pior, e deveria ser tratado como um bug. O que usr prova é que internamente C # é mais parecido com C do que qualquer um de nós pensava. Se o código que faz isso deve ser considerado válido é outra questão.
Marc L.
4

O xor condicional não existe, mas você pode usar um lógico porque xor é definido para booleanos e todas as comparações condicionais são avaliadas como booleanos.

Então você pode dizer algo como:

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

}
Klark
fonte
É um operador binário, não lógico. Ele assume que os bools são 0 ou 1, o que não é verdadeiro no CLR. Portanto, este código pode realmente não funcionar.
usr
@usr, o que você quer dizer com CLR? Isso funcionou para mim, não tenho certeza se perdi um caso extremo aqui ...
LunaCodeGirl
3
@Spencevail você provavelmente não estava pensando no caso de um booleano não falso não ter representação inteira 1. Este é um fato pouco conhecido. Você pode acabar em uma situação onde o xor de dois booleanos não falsos ainda é não falso! Dito isso, neste código em particular, o operador xor só é aplicado a valores em [0,1], de modo que meu comentário não se aplica (totalmente).
usr
1
@Spencevail esse é exatamente o caso que pode falhar. É possível criar uma função de código gerenciado segura CreateBool (byte) que converte um byte em um bool dos mesmos bits. Então, CreateBool (1) ^ CreateBool (2) é verdadeiro, mas CreateBool (1) é verdadeiro e CreateBool (2) também é verdadeiro! &também é vulnerável.
usr
1
Na verdade, acabei de relatar um bug do RyuJIT porque eles não consideraram essa possibilidade e compilaram &&como se fosse &uma compilação incorreta.
usr
3

Embora haja um operador xor lógico^ , não há operador xor condicional . Você pode obter um xor condicional de dois valores A e B usando o seguinte:

A ? (!B) : B

Os parênteses não são necessários, mas eu os adicionei para maior clareza.

Como apontado por The Evil Greebo, isso avalia ambas as expressões, mas xor não pode ser curto-circuitado como e e ou .

Jimreed
fonte
Qual é a diferença entre um logican ^ e um condicional ^? oO
Armen Tsirunyan
@Armen Tsirunyan Os operadores lógicos realizam operações bit a bit em tipos onde isso faz sentido, enquanto os operadores condicionais operam em valores booleanos e retornam um resultado booleano. Considerando os valores booleanos: 0101 ^ 0011tem o valor 0110.
jimreed
3
não, você está completamente errado. existem ambos os tipos de XOR (eles são chamados de bit a bit e lógico, respectivamente) em C #. Ambos usam o símbolo ^.
Armen Tsirunyan
1

você pode usar:

a = b ^ c;

assim como em c / c ++

Gulyan
fonte
0

Não existe XOR condicional (curto-circuito). Os operadores condicionais só são significativos quando há uma maneira de determinar definitivamente o resultado final olhando apenas para o primeiro argumento. XOR (e adição) sempre requerem dois argumentos, portanto, não há como entrar em curto-circuito após o primeiro argumento.

Se você souber A = verdadeiro, então (A XOR B) =! B.

Se você souber A = falso, então (A XOR B) = B.

Em ambos os casos, se você conhece A, mas não B, então não sabe o suficiente para saber (A XOR B). Você deve sempre aprender os valores de A e B para calcular a resposta. Não existe literalmente nenhum caso de uso em que você possa resolver o XOR sem os dois valores.

Lembre-se de que o XOR, por definição, tem quatro casos:

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

Mais uma vez, espero que seja óbvio pelo que foi dito acima que saber o primeiro valor nunca é suficiente para obter a resposta sem também saber o segundo valor. No entanto, em sua pergunta, você omitiu o primeiro caso. Se você ao invés quisesse

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

então você pode realmente conseguir isso por uma operação condicional de curto-circuito:

A && !B

Mas isso não é um XOR.

Kevin holt
fonte
Não estou vendo nada nesta resposta que não esteja em pelo menos uma das respostas acima. Não vejo qualquer indicação de que seu un-xor em curto-circuito seja o que OP estava procurando, uma vez que ele aceitou uma resposta que presume que ele queria o xor adequado.
15ee8f99-57ff-4f92-890c-b56153
A minha é literalmente a única resposta sugerida até agora que pode produzir a tabela verdade solicitada do OP sem avaliar o segundo argumento.
Kevin Holt de
Além disso, o OP perguntou por que não há XOR condicional, e embora as respostas acima digam corretamente que é porque XOR requer dois argumentos, IMO as respostas acima não parecem explicar suficientemente POR QUE XOR realmente precisa de dois argumentos. Obviamente, você pensa o contrário, mas para mim ficou claro a partir dos vários comentários nesta página que a argumentação básica de dois argumentos do XOR ainda não havia sido totalmente explicada para um iniciante completo.
Kevin Holt
1
Você me convenceu.
15ee8f99-57ff-4f92-890c-b56153
@Kevin Holt - Logical XOR é significativo se você precisa que uma das condições seja verdadeira, mas não ambas. Que você tenha que avaliar ambas as condições, não importa. O curto-circuito é um detalhe de baixo nível com o qual você só precisa se preocupar ao lidar com código crítico de desempenho (o fluxo de controle é lento). Eu ficaria mais preocupado com o que 'exclusivo ou' deve significar ao transformá-lo em um operador lógico. A saber, faça com que opere como a versão bit a bit (como os outros operadores) ou torne-o um ou que seja exclusivo (quantas condições você quiser, mas apenas uma pode ser verdadeira).
Thorham
-3

Essa pergunta foi respondida afetivamente, mas me deparei com uma situação diferente. É verdade que não há necessidade de um XOR condicional. Também é verdade que o operador ^ pode ser usado. No entanto, se você precisar apenas testar o status "verdadeiro || falso" dos operandos, ^ pode causar problemas. Por exemplo:

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...
    }
}

Neste exemplo, se a esquerda for definida como 10 (0xa) e a direita como 5 (0x5), o desvio "sucesso" é inserido. Para este exemplo (simplista, se bobo), isso resultaria em um bug, já que você não deve virar à esquerda E à direita ao mesmo tempo. O que deduzi do questionador não é que ele realmente queria uma condicional, mas uma maneira simples de executar verdadeiro / falso nos valores passados ​​para xor.

Uma macro pode resolver o problema:

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

Sinta-se à vontade para me dar um tapa se eu errar o alvo: o)

Eu li a resposta de Jimreed abaixo depois de postar isso (Yapdog ruim!) E a dele é realmente mais simples. Funcionaria e eu não tenho absolutamente nenhuma ideia de por que sua resposta foi rejeitada ...

Yap Dog
fonte
3
Esta é uma questão C #, não C / C ++. ifrequer uma expressão booleana, nem mesmo é compilada com um int.
Marc L.