XOR conditionnel?

87

Comment se fait-il que C # n'ait pas d' XORopérateur conditionnel ?

Exemple:

true  xor false = true
true  xor true  = false
false xor false = false
Gilad Naaman
la source
15
Comment !=fonctionne comme substitut?
Pascal Cuoq
45
C # n'avoir un opérateur XOR (x ^ y). Je nie donc la prémisse de la question. Pouvez-vous expliquer pourquoi vous pensez que C # n'a pas d'opérateur xor? Je suis intéressé d'apprendre pourquoi les gens croient à de fausses choses à propos de C #.
Eric Lippert
3
@Eric Lippert: Je pense qu'il fait référence aux opérateurs logiques ( & | ^) vs opérateurs conditionnels ( && ||). Mais vous avez raison (bien sûr), il y a un XOR logique ...
BoltClock
14
@BoltClock: Oh, si la question est "pourquoi n'y a-t-il pas d'opérateur xor de court-circuit?" - comment pourrait-il y en avoir? Avec "et" si le premier argument est faux, vous n'avez pas besoin d'évaluer le second. Avec "ou", si le premier argument est vrai, vous n'avez pas besoin d'évaluer le second. Vous devez toujours évaluer les deux arguments pour xor, il n'y a donc pas de court-circuit possible.
Eric Lippert
4
La question elle-même est mieux adaptée à Microsoft - et c'est donc une bonne raison de voter contre - mais si celui qui l'a refusé l'a fait à cause de l'opérateur ^, alors vous devez lire avec plus d'attention aux détails, car la question était conditionnelle vs. logique, pas simplement "pourquoi n'y a-t-il pas de XOR".
The Evil Greebo

Réponses:

121

En C #, les opérateurs conditionnels n'exécutent leur opérande secondaire que si nécessaire .

Puisqu'un XOR doit par définition tester les deux valeurs, une version conditionnelle serait idiote.

Exemples :

  • ET logique: &- teste les deux côtés à chaque fois.

  • OU logique: |- testez les deux côtés à chaque fois.

  • ET conditionnel: &&- ne teste le 2ème côté que si le 1er côté est vrai.

  • OR conditionnel: ||- tester uniquement le 2ème côté si le 1er côté est faux.

Le mal Greebo
la source
35
Un opérateur XOR ne violerait pas la convention "les opérateurs conditionnels n'exécutent leur opérande secondaire que si nécessaire". Ce serait juste toujours nécessaire.
Nathan Kovner
2
Conditionnel XOR pourrait être un raccourci agréable et élégant pour certains modèles particuliers, mais pas sûr qu'il soit suffisamment justifié pour l'inclure dans la langue. Un exemple de tels modèles où XOR peut s'avérer utile, est la négation conditionnelle: lorsqu'une expression booléenne doit être niée ou non, étant donné une deuxième expression booléenne.
SalvadorGomez
1
Je n'ai pas répondu à cela depuis un certain temps, mais pour répondre au commentaire populaire de @KhyadHalda: Pourquoi avez-vous jamais construit quelque chose dont vous savez qu'il ne sera jamais utilisé? Vous écririez délibérément du code mort.
The Evil Greebo
Étant donné qu'un opérateur XOR conditionnel ne violerait pas la convention que vous définissez (commentaire de Khyad), couplé avec le fait qu'il serait réellement utile dans certains cas, il nie pratiquement toute "bêtise" que vous attribuez à un tel opérateur existant.
Syndog
1
Comment, jamais, un XOR conditionnel serait-il jamais utile? Un XOR conditionnel ne peut jamais évaluer sans comparer les deux côtés pour déterminer qu'ils sont égaux ou non. Même la notion de XOR conditionnel comparant deux booléens doit toujours vérifier la valeur de chaque booléen et tester l'égalité.
The Evil Greebo
280

La question est un peu dépassée mais ...

C'est ainsi que doit fonctionner cet opérateur:

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

Voici comment l'opérateur! = Fonctionne avec les types booléens:

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

Ainsi, comme vous le voyez, inexistante ^^peut être remplacée par une!=

piotrpo
la source
46
C'est en fait la seule réponse qui répond directement et correctement à la question.
usr
39
Je suis assis ici en me faisant face à moi-même que je ne savais pas que !=cela fonctionnerait.
AdamMc331
1
La réponse est correcte mais les commentaires ne le sont pas. Il ne répond pas à la question, qui est "pourquoi C # n'a-t-il pas un XOR conditionnel?". Ce n'est pas à proprement parler un opérateur logique, c'est un opérateur d'égalité relationnelle. Bien que le résultat soit le même que XOR, il est dans une classe différente. Il se compare uniquement à XOR lors du test de deux valeurs booléennes, et les deux côtés de l'opérateur doivent toujours être évalués.
The Evil Greebo
3
@TheEvilGreebo - Ce que vous dites est vrai; l'opérateur! = n'est pas techniquement un opérateur XOR conditionnel. Cependant, cette réponse dit effectivement: "Un opérateur XOR conditionnel n'existe pas parce que l'opérateur! = Existe." C'est comme ça que je l'ai lu, de toute façon.
Syndog
6
Je pense que presque tout le monde a fini à ce post voulait en fait écrire XOR sur les booléens. comme il est logique ANDet ORmais rien de plus XOR. ou du moins nous n'avons pas réalisé !=:) @TheEvilGreebo
M.kazem Akhgary
30

Il y a l'opérateur logique XOR: ^

Documentation: opérateurs C # et opérateur ^

glace
la source
2
Logique, non conditionnelle. Logique et = &, conditionnel et = &&. Il pose des questions sur le conditionnel.
The Evil Greebo
3
C'est binaire, pas logique. Il suppose que les booléens valent 0 ou 1, ce qui n'est pas vrai sur le CLR.
usr
1
désolé, cette réponse ne répond pas réellement à la question sur les opérateurs CONDITIONNELS. c'est un peu opperator
Nathan Tregillus
2
Pour mémoire, la documentation liée dans cette réponse indique explicitement que ^, lorsqu'il est utilisé avec des opérandes booléens, est un opérateur booléen. "pour les opérandes booléens, l'opérateur ^ calcule le même résultat que l'opérateur d'inégalité! =". Vous pouvez également utiliser des opérandes entiers xor bit à bit avec ^. C # n'est pas C.
15ee8f99-57ff-4f92-890c-b56153
24

Pour clarifier, l'opérateur ^ fonctionne avec les types intégraux et booléens.

Voir l'opérateur ^ de MSDN (référence C #) :

Les opérateurs binaires ^ sont prédéfinis pour les types intégraux et booléens. Pour les types intégraux, ^ calcule le OU exclusif au niveau du bit de ses opérandes. Pour les opérandes booléens, ^ calcule le ou exclusif logique de ses opérandes; autrement dit, le résultat est vrai si et seulement si exactement l'un de ses opérandes est vrai.

Peut-être que la documentation a changé depuis 2011 lorsque cette question a été posée.

RichardCL
la source
2
programmé en c # depuis longtemps, je ne l'ai jamais su! merci @RichardCL!
Nathan Tregillus
Il s'agit d'une bonne information mais semble plus appropriée comme commentaire ou modification de l'autre réponse qui mentionne ^et précède celle-ci de cinq ans. Je doute que quelque chose ait changé.
Chris
13

Comme demandé par Mark L , voici la version correcte:

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

Voici la table de vérité:

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

Référence: OU exclusif

Fellow simple
la source
2
La question posée était: POURQUOI C # n'a-t-il pas d'opérateur XOR conditionnel. Cela ne répond pas à la question. Quant à la fonction elle-même: cette fonction fonctionne comme un XOR conditionnel - quelle que soit la question, est-il plus efficace que le XOR non conditionnel? Afin de tester la vérité exclusive, XOR doit confirmer qu'un seul et exactement un résultat est vrai. Cela signifie que les deux côtés doivent être évalués et comparés. La fonction ci-dessus teste les deux côtés d'une condition et tout en inversant une valeur, au minimum. Savons-nous en interne si c'est différent de XOR?
The Evil Greebo
6

Oh oui, c'est vrai.

bool b1 = true;
bool b2 = false;
bool XOR = b1 ^ b2;
Armen Tsirunyan
la source
1
C'est un opérateur binaire, pas un opérateur logique. Il suppose que les booléens valent 0 ou 1, ce qui n'est pas vrai sur le CLR. Donc, ce code peut échouer à fonctionner.
usr
6
@usr, En C #, l'opérateur ^ est logique lorsqu'il est appliqué à deux opérandes booléens. Vous avez énormément commenté à travers ces réponses, avez-vous déjà exécuté du code pour tester votre hypothèse?
Marc L.
2
@MarcL. J'ai fait: pastebin.com/U7vqpn6G Imprime true, bien que true ^ true soit censé être faux. bool n'est pas toujours égal à 0 ou 1. Ce n'est pas un type logique sur le CLR. C'est une quantité de 8 bits avec un contenu arbitraire. J'aurais pu générer une IL vérifiable pour démontrer également le problème.
usr
2
Lors de l'utilisation d'autres langages CLR que C # par exemple. Je le répète: j'aurais pu utiliser ILASM pour créer un assembly entièrement vérifiable et sûr qui fait cela (au niveau IL, une valeur booléenne est juste un i1, tout comme un octet). Il s'agit d'un comportement défini et géré à 100%. Le CLR n'est pas grossier .; La première fois que j'ai vu ce comportement, c'était lors de l'utilisation de Microsoft Pex.
usr
1
@EdPlunkett, je ne pense pas que votre camion soit avec moi. usr a montré qu'en interne, il s'agit en fait d'un opérateur binaire . L '«abus» dont je me plaignais était le moyen par lequel il l'a prouvé, ce que je maintiens toujours trop énervé. Cela peut arriver, mais met l'utilisation de Boolean si complètement dans le no man's land que le déployer en tant que CLR-safe serait au mieux dangereux, abusif (sinon malveillant) au pire, et devrait être traité comme un bogue. Ce que usr prouve, c'est qu'en interne C # ressemble plus à C qu'aucun de nous ne le pensait. La question de savoir si le code qui fait cela doit être considéré comme valide est une autre question.
Marc L.
4

Le xor conditionnel n'existe pas, mais vous pouvez en utiliser un logique car xor est défini pour les booléens et toutes les comparaisons conditionnelles sont évaluées en booléens.

Vous pouvez donc dire quelque chose comme:

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

}
Klark
la source
C'est un opérateur binaire, pas un opérateur logique. Il suppose que les booléens valent 0 ou 1, ce qui n'est pas vrai sur le CLR. Donc, ce code peut échouer à fonctionner.
usr
@usr que voulez-vous dire CLR? Cela a fonctionné pour moi, je ne sais pas si j'ai raté un cas de pointe ici ...
LunaCodeGirl
3
@Spencevail vous ne pensiez probablement pas au cas où un booléen non faux pourrait ne pas avoir de représentation entière 1. C'est un fait peu connu. Vous pouvez vous retrouver dans une situation où le xor de deux booléens non faux est toujours non faux! Cela dit dans ce code particulier, l'opérateur xor n'est jamais appliqué qu'aux valeurs de [0,1] afin que mon commentaire ne s'applique pas (entièrement).
usr
1
@Spencevail c'est exactement le cas qui peut échouer. Il est possible de créer une fonction de code géré sécurisé CreateBool (octet) qui convertit un octet en un booléen des mêmes bits. Ensuite, CreateBool (1) ^ CreateBool (2) est vrai, mais CreateBool (1) est vrai et CreateBool (2) est vrai aussi! &est également vulnérable.
usr
1
En fait, je viens de signaler un bug RyuJIT car ils n'ont pas envisagé cette possibilité et compilé &&comme si c'était &une mauvaise compilation.
usr
3

Bien qu'il existe un opérateur xor logique^ , il n'y a pas d' opérateur xor conditionnel . Vous pouvez obtenir un xor conditionnel de deux valeurs A et B en utilisant ce qui suit:

A ? (!B) : B

Les parens ne sont pas nécessaires, mais je les ai ajoutés pour plus de clarté.

Comme l'a souligné The Evil Greebo, cela évalue les deux expressions, mais xor ne peut pas être court-circuité comme et et ou .

Jimreed
la source
Quelle est la différence entre un logican ^ et un conditionnel ^? oO
Armen Tsirunyan
@Armen Tsirunyan Les opérateurs logiques effectuent des opérations au niveau du bit dans les types où cela a du sens tandis que les opérateurs conditionnels opèrent sur des valeurs booléennes et renvoient un résultat booléen. Considérant les valeurs booléennes: 0101 ^ 0011a la valeur 0110.
jimreed
3
non, vous vous trompez complètement. il existe deux types de XOR (ils sont appelés respectivement bit à bit et logique) en C #. Les deux utilisent le symbole ^.
Armen Tsirunyan
1

vous pouvez utiliser:

a = b ^ c;

comme en c / c ++

Gulyan
la source
0

Il n'existe pas de XOR conditionnel (court-circuit). Les opérateurs conditionnels n'ont de sens que lorsqu'il existe un moyen de déterminer définitivement le résultat final en ne regardant que le premier argument. XOR (et l'addition) nécessitent toujours deux arguments, il n'y a donc aucun moyen de court-circuiter après le premier argument.

Si vous connaissez A = vrai, alors (A XOR B) =! B.

Si vous connaissez A = faux, alors (A XOR B) = B.

Dans les deux cas, si vous connaissez A mais pas B, alors vous n'en savez pas assez pour savoir (A XOR B). Vous devez toujours apprendre les valeurs de A et de B pour calculer la réponse. Il n'y a littéralement aucun cas d'utilisation où vous pouvez résoudre le XOR sans les deux valeurs.

Gardez à l'esprit que XOR a par définition quatre cas:

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

Encore une fois, j'espère qu'il est évident d'après ce qui précède que connaître la première valeur n'est jamais suffisant pour obtenir la réponse sans connaître également la deuxième valeur. Cependant, dans votre question, vous avez omis le premier cas. Si tu voulais plutôt

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

alors vous pouvez en effet l'obtenir par une opération conditionnelle de court-circuit:

A && !B

Mais ce n'est pas un XOR.

Kevin Holt
la source
Je ne vois rien dans cette réponse qui ne soit pas dans au moins une réponse ci-dessus. Je ne vois aucune indication que votre un-xor court-circuitable soit ce qu'OP recherchait, puisqu'il a accepté une réponse qui suppose qu'il voulait un xor approprié.
15ee8f99-57ff-4f92-890c-b56153
La mienne est littéralement la seule réponse suggérée jusqu'à présent qui puisse produire la table de vérité demandée par l'OP sans évaluer le deuxième argument.
Kevin Holt
De plus, l'OP a demandé pourquoi il n'y a pas de XOR conditionnel, et bien que les réponses ci-dessus indiquent correctement que c'est parce que XOR nécessite deux arguments, l'OMI les réponses ci-dessus ne semblent pas expliquer suffisamment pourquoi XOR a réellement besoin de deux arguments. Évidemment, vous pensez autrement, mais pour moi, il était évident d'après les différents commentaires sur cette page que les deux arguments de base de XOR n'avaient pas encore été pleinement expliqués à un débutant complet.
Kevin Holt
1
Vous m'en avez parlé.
15ee8f99-57ff-4f92-890c-b56153
@Kevin Holt - Le XOR logique est significatif si vous avez besoin que l'une des conditions soit vraie mais pas les deux. Que vous deviez évaluer les deux conditions n'a pas d'importance. Le court-circuit est un détail de bas niveau dont vous n'avez à vous soucier que lorsque vous traitez du code critique pour les performances (le flux de contrôle est lent). Je serais plus préoccupé par ce que «exclusif ou» est censé signifier lorsque l'on en fait un opérateur logique. À savoir, faites-le fonctionner comme la version bit à bit (comme les autres opérateurs), ou faites-en un ou c'est exclusif (autant de conditions que vous le souhaitez, mais une seule peut être vraie).
Thorham
-3

Cette question a reçu une réponse affective, mais je suis tombé sur une situation différente. Il est vrai qu'il n'y a pas besoin d'un XOR conditionnel. Il est également vrai que l'opérateur ^ peut être utilisé. Cependant, si vous avez seulement besoin de tester le statut "true || false" des opérandes, alors ^ peut entraîner des problèmes. Par exemple:

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

Dans cet exemple, si la gauche est définie sur 10 (0xa) et la droite sur 5 (0x5), la branche «succès» est entrée. Pour cet exemple (simpliste si idiot), cela entraînerait un bogue puisque vous ne devriez pas tourner à gauche ET à droite en même temps. Ce que j'ai compris du questionneur n'est pas qu'il voulait en fait un conditionnel, mais un moyen simple d'effectuer le vrai / faux sur les valeurs transmises au xor.

Une macro pourrait faire l'affaire:

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

N'hésitez pas à me gifler si je suis hors de propos: o)

J'ai lu la réponse de Jimreed ci-dessous après avoir posté ceci (mauvais Yapdog!) Et la sienne est en fait plus simple. Cela fonctionnerait et je n'ai absolument aucune idée de la raison pour laquelle sa réponse a été rejetée ...

Chien Yap
la source
3
C'est une question C #, pas C / C ++. ifnécessite une expression booléenne, il ne se compilera même pas avec un int.
Marc L.