web-dev-qa-db-fra.com

Logique XOR opérateur en C ++?

Une telle chose existe t elle? C’est la première fois que je rencontre un besoin pratique, mais je n’en vois pas d’énuméré dans Stroustrup . J'ai l'intention d'écrire:

// Detect when exactly one of A,B is equal to five.
return (A==5) ^^ (B==5);

Mais il n'y a pas d'opérateur ^^. Puis-je utiliser le ^ au niveau des bits ici et obtenir la bonne réponse (quelle que soit la représentation réelle ou fausse de la machine)? Je ne mélange jamais & et &&, ni | et ||, alors j'hésite à le faire avec ^ et ^^.

Je serais plus à l'aise d'écrire ma propre fonction bool XOR(bool,bool) à la place.

266
RAC

L'opérateur != remplit cette fonction pour les valeurs bool.

495
Greg Hewgill

Pour une vraie opération logique XOR, cela fonctionnera:

if(!A != !B) {
    // code here
}
223
LiraNuna

L’implémentation manuelle correcte logique XOR dépend de la précision avec laquelle vous souhaitez reproduire le comportement général d’autres opérateurs logiques (|| et &&) avec votre XOR. Deux aspects importants concernent ces opérateurs: 1) ils garantissent l’évaluation des courts-circuits, 2) ils introduisent un point de séquence, 3) ils n’évaluent leurs opérandes qu’une seule fois.

Comme vous l'avez compris, l'évaluation XOR ne peut pas être court-circuitée car le résultat dépend toujours des deux opérandes. Donc, 1 est hors de question. Mais qu'en est-il de 2? Si vous ne vous souciez pas de 2, alors avec les valeurs normalisées (c'est-à-dire bool), l'opérateur != exécute le travail de XOR en termes de résultat. Et les opérandes peuvent être facilement normalisés avec unaire !, si nécessaire. Ainsi, !A != !B implémente le XOR approprié à cet égard.

Mais si vous vous souciez du point de séquence supplémentaire, ni !=, ni au niveau du bit ^ n'est le moyen approprié d'implémenter XOR. Une façon possible de faire correctement XOR (a, b) pourrait ressembler à:

a ? !b : b

C’est en fait aussi près que possible de la fabrication d’un XOR fait maison, similaire à || et &&. Bien entendu, cela ne fonctionnera que si vous implémentez votre XOR en tant que macro. Une fonction ne fera pas l'affaire, car le séquençage ne s'appliquera pas aux arguments de la fonction.

Quelqu'un pourrait dire cependant que la seule raison d'avoir un point de séquence à chaque && et || est de prendre en charge l'évaluation court-circuitée, et donc XOR n'en a pas besoin. Cela a du sens, en fait. Cependant, il est utile d’envisager un XOR avec un point de séquence au milieu. Par exemple, l'expression suivante

++x > 1 && x < 5

a un comportement défini et un résultat spécifique en C/C++ (en ce qui concerne le séquençage au moins). Donc, on peut raisonnablement attendre la même chose de la part de l'utilisateur logique XOR, comme dans

XOR(++x > 1, x < 5)

alors qu'un != basé sur XOR n'a pas cette propriété.

40
AnT

Il y a une autre façon de faire XOR:

bool XOR(bool a, bool b)
{
    return (a + b) % 2;
}

Ce qui peut évidemment être démontré pour fonctionner via:

#include <iostream>

bool XOR(bool a, bool b)
{
    return (a + b) % 2;
}

int main()
{
    using namespace std;
    cout << "XOR(true, true):\t" << XOR(true, true) << endl
         << "XOR(true, false):\t" << XOR(true, false) << endl
         << "XOR(false, true):\t" << XOR(false, true) << endl
         << "XOR(false, false):\t" << XOR(false, false) << endl
         << "XOR(0, 0):\t\t" << XOR(0, 0) << endl
         << "XOR(1, 0):\t\t" << XOR(1, 0) << endl
         << "XOR(5, 0):\t\t" << XOR(5, 0) << endl
         << "XOR(20, 0):\t\t" << XOR(20, 0) << endl
         << "XOR(6, 6):\t\t" << XOR(5, 5) << endl
         << "XOR(5, 6):\t\t" << XOR(5, 6) << endl
         << "XOR(1, 1):\t\t" << XOR(1, 1) << endl;
    return 0;
}
26
Bertie Wheen

L'opérateur XOR ne peut pas être court-circuité; c'est-à-dire que vous ne pouvez pas prédire le résultat d'une expression XOR simplement en évaluant son opérande de gauche. Il n’ya donc aucune raison de fournir une version ^^.

18
Mehrdad Afshari

Il y avait quelques bons codes postés qui ont résolu le problème mieux que! A! =! B

Notez que je devais ajouter BOOL_DETAIL_OPEN/CLOSE pour que cela fonctionne sur MSVC 2010

/* From: http://groups.google.com/group/comp.std.c++/msg/2ff60fa87e8b6aeb

   Proposed code    left-to-right?  sequence point?  bool args?  bool result?  ICE result?  Singular 'b'?
   --------------   --------------  ---------------  ---------- ------------  -----------  -------------
   a ^ b                  no              no             no          no           yes          yes
   a != b                 no              no             no          no           yes          yes
   (!a)!=(!b)             no              no             no          no           yes          yes
   my_xor_func(a,b)       no              no             yes         yes          no           yes
   a ? !b : b             yes             yes            no          no           yes          no
   a ? !b : !!b           yes             yes            no          no           yes          no
   [* see below]          yes             yes            yes         yes          yes          no
   (( a bool_xor b ))     yes             yes            yes         yes          yes          yes

   [* = a ? !static_cast<bool>(b) : static_cast<bool>(b)]

   But what is this funny "(( a bool_xor b ))"? Well, you can create some
   macros that allow you such a strange syntax. Note that the
   double-brackets are part of the syntax and cannot be removed! The set of
   three macros (plus two internal helper macros) also provides bool_and
   and bool_or. That given, what is it good for? We have && and || already,
   why do we need such a stupid syntax? Well, && and || can't guarantee
   that the arguments are converted to bool and that you get a bool result.
     Think "operator overloads". Here's how the macros look like:

   Note: BOOL_DETAIL_OPEN/CLOSE added to make it work on MSVC 2010
  */

#define BOOL_DETAIL_AND_HELPER(x) static_cast<bool>(x):false
#define BOOL_DETAIL_XOR_HELPER(x) !static_cast<bool>(x):static_cast<bool>(x)

#define BOOL_DETAIL_OPEN (
#define BOOL_DETAIL_CLOSE )

#define bool_and BOOL_DETAIL_CLOSE ? BOOL_DETAIL_AND_HELPER BOOL_DETAIL_OPEN
#define bool_or BOOL_DETAIL_CLOSE ? true:static_cast<bool> BOOL_DETAIL_OPEN
#define bool_xor BOOL_DETAIL_CLOSE ? BOOL_DETAIL_XOR_HELPER BOOL_DETAIL_OPEN
13
elegant dice

Utilisez un simple:

return ((op1 ? 1 : 0) ^ (op2 ? 1 : 0));
6
tiands

Voici comment je pense que vous écrivez une comparaison XOR en C++:

bool a = true;   // Test by changing to true or false
bool b = false;  // Test by changing to true or false
if (a == !b)     // THIS IS YOUR XOR comparison
{
    // do whatever
}

Preuve

XOR TABLE
 a   b  XOR
--- --- ---
 T   T   F
 T   F   T
 F   T   T
 F   F   F

a == !b TABLE
 a   b  !b  a == !b
--- --- --- -------
 T   T   F     F
 T   F   T     T
 F   T   F     T
 F   F   T     F

La preuve en est qu’une étude exhaustive des entrées et des sorties montre que, dans les deux tableaux, le résultat est toujours identique pour chaque jeu d’entrées.

Par conséquent, la question initiale étant comment écrire:

return (A==5) ^^ (B==5)

La réponse serait

return (A==5) == !(B==5);

Ou si vous aimez, écrivez

return !(A==5) == (B==5);
5
Indinfer

(A || B) && !(A && B)

La première partie est A OR B, qui est le OU inclusif; la deuxième partie est, PAS A ET B. Ensemble, vous obtenez A ou B, mais pas les deux A et B.

Ceci fournira le XOR prouvé dans la table de vérité ci-dessous.

|-----|-----|-----------|
|  A  |  B  |  A XOR B  |
|-----|-----|-----------|
|  T  |  T  |   False   |
|-----|-----|-----------|
|  T  |  F  |   True    |
|-----|-----|-----------|
|  F  |  T  |   True    |
|-----|-----|-----------|
|  F  |  F  |   False   |
|-----|-----|-----------|
4
Eat at Joes

J'utilise "xor" (il semble que ce soit un mot clé; dans Code :: Blocks au moins, il devient gras) tout comme vous pouvez utiliser "et" au lieu de && et "ou" à la place de ||.

if (first xor second)...

Oui, c'est au niveau des bits. Pardon.

1
csiz
#if defined(__OBJC__)
    #define __bool BOOL
    #include <stdbool.h>
    #define __bool bool
#endif

static inline __bool xor(__bool a, __bool b)
{
    return (!a && b) || (a && !b);
}

Cela fonctionne comme défini. Les conditions sont à détecter si vous utilisez Objective-C , qui demande BOOL au lieu de bool (la longueur est différente!)

0
Maxthon Chan