C ++의 논리 XOR 연산자?


292

그런 것이 있습니까? 실용적으로 필요한 것은 처음이지만 Stroustrup에 나열된 것은 보이지 않습니다 . 나는 쓰려고한다 :

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

그러나 ^^연산자 는 없습니다 . ^여기 에서 비트 단위를 사용하여 (참과 거짓의 기계 표현에 관계없이) 정답을 얻을 수 있습니까? 나는 결코 혼합 &하고 &&, 또는 |||내가 함께 그렇게 주저 있도록 ^하고 ^^.

bool XOR(bool,bool)대신 내 자신의 함수를 작성하는 것이 더 편할 것입니다.


57
사실, Jim, 그것은 &와 && 사이의 유일한 차이점은 아닙니다. 예를 들어 1 && 2는 True입니다. 그러나 1 & 2 => 0입니다. 그 때문에 "short circuiting"은 단지 발생하는 속성이라고 생각합니다. 논리는 더 중요한 기능입니다 ...
Brian Postow

6
2 && 3 == true, 2 & 3 == 2는 말할 것도 없습니다.
David Thornley

1
David Thomley : 글쎄요,하지만 2 ==> 맞습니다. 그래도 괜찮습니다 ... 기억하세요, 부울은 실제로 없습니다 ...
Brian Postow

13
@BrianPostow : 실제로 C ++에는 있습니다.
Adrian Willenbücher

7
아래에 게시 된 것처럼 왜 존재하지 않는지에 대한 Dennis Ritchie의 답변입니다. c-faq.com/misc/xor.dmr.html
Tobia

답변:


536

!=오퍼레이터는이 목적을 제공 bool값.


7
그러나 false! = false => false
Jonas

13
이것은 부울에만 적용됩니다. 그리고 ^는 완벽하게 잘 작동 할 것입니다. 2! = 1 => 1 이것은 당신이 원하는 것이 아닙니다! LiraNuna가 말한 것처럼! 양쪽의 infront는 그 문제를 해결합니다. 그러나 다시, 당신은 ^ ... 비트 단위로 사용할 수 있습니다
브라이언 Postow

8
bool부울이 아닌 사용자가 원하는 것을 수행하지 않아도되기 때문에 " 값 에 대해"언급하는 데주의를 기울였습니다 . 그리고 이것이 C ++이기 때문에 그 목적 bool으로 사용해야 int하는 대신 실제 유형 이 있습니다.
Greg Hewgill

29
당신이 형식을 위해 그것을하고 싶다면 a그냥 쓰기!(a) != !(a)
Chris Lutz

6
@ChrisLutz : 예. 그러나 과부하 된 연산자는 조심하십시오.
rwong

246

진정한 논리적 XOR 연산의 경우 다음과 같이 작동합니다.

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

(가) 주 !이 개 동일하지 않은 양의 정수 (각각은 그래서, 부울에 값이 변환하고이를 부정 true)로 평가 것입니다 false.


6
왜 A와 B가 부정되는지 이해가되지 않습니다!
Martin Hansen

26
주로 부울로 변환합니다. !!그냥 잘 부탁하지만, 달라야하기 때문에 해치지 않습니다.
LiraNuna

4
문제는 컴파일러가 이것을 올바르게 최적화 할 수 있다는 것입니다.
einpoklum

6
bools 표준화의 중요성을 알지 못하면 2 일이 걸렸습니다.
Makan Tayebi

9
@LiraNuna, "왜 A와 B가 부정인가!" / "주로 부울로 변환합니다." -나는 이것이 대답에서 언급 할 가치가 있다고 생각합니다.
cp.engr

42

적절한 수동 논리 XOR 구현은 XOR과 다른 논리 연산자 ( ||&&) 의 일반적인 동작을 모방하려는 정도에 따라 다릅니다 . 이 연산자에는 두 가지 중요한 사항이 있습니다. 1) 단락 평가를 보장합니다. 2) 시퀀스 포인트를 소개합니다. 3) 피연산자를 한 번만 평가합니다.

XOR 평가는 결과가 항상 두 피연산자에 의존하기 때문에 단락 될 수 없습니다. 따라서 1은 의문의 여지가 없습니다. 그러나 2는 어떻습니까? 2를 신경 쓰지 않으면 정규화 된 (즉 bool) 값을 사용하여 연산자 !=는 결과 측면에서 XOR의 작업을 수행합니다. !필요한 경우 피연산자는 단항으로 쉽게 정규화 할 수 있습니다 . 따라서 !A != !B적절한 XOR을 구현합니다.

그러나 추가 시퀀스 포인트에 관심이 있다면 XOR을 구현하는 적절한 방법 !=도 비트 단위 도 아닙니다 ^. XOR (a, b)를 올바르게 수행하는 한 가지 방법은 다음과 같습니다.

a ? !b : b

이것은 실제로 수제 XOR을 "유사한" ||및에 가깝게 만들 수있는 한 가깝습니다 &&. 물론 XOR을 매크로로 구현 한 경우에만 작동합니다. 시퀀싱은 함수의 인수에 적용되지 않으므로 함수는 수행되지 않습니다.

누군가가 각각의 시퀀스 지점을 가지고있는 유일한 이유는 것을,하지만 말할 수 &&||이다는 단락 평가를 지원하기 때문에 XOR 하나 필요하지 않습니다. 이것은 실제로 의미가 있습니다. 그러나 중간에 시퀀스 포인트가있는 XOR을 갖는 것이 좋습니다. 예를 들어, 다음 표현식

++x > 1 && x < 5

C / C ++에서 동작을 정의하고 결과를 구체화했습니다 (적어도 시퀀싱과 관련하여). 따라서 사용자 정의 논리 XOR 과 동일한 것을 합리적으로 기대할 수 있습니다 .

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

A는 동안 !=기반 XOR이 속성이 없습니다.


1
당신은 ||and &&: C) 에 대해 다른 중요한 것을 놓쳤습니다 . 부울 컨텍스트에서 피연산자를 평가합니다. 즉, 0 1 && 2과 달리 사실 1 & 2입니다. 마찬가지로, ^^연산자는 부울 컨텍스트에서 피연산자를 평가하는이 추가 기능을 제공하는 데 유용 할 수 있습니다. 예를 들어 1 ^^ 2(와 달리 1 ^ 2) 거짓 입니다.
Craig McQueen

2
@Craig McQueen : 나는 그것을 놓치지 않았다. 내 게시물의 두 번째 단락에서 언급합니다. 제 생각에는 피연산자를 부울 값으로 취급하는 것은 논리 연산자의 중요한 기능이 아니며 그 이유 때문에 피연산자가 소개되지 않을 것이라는 점입니다. 그들이 소개 된 주된 이유는 단락 평가와 그에 필요한 시퀀스 포인트 때문입니다.
AnT

요즘 귀하의 제안은 여전히 ​​매크로에서만 작동합니까? 함수에서 평가할 매개 변수의 순서가 컴파일러에 따라 다르다는 것은 사실이지만 현재 왼쪽에서 오른쪽으로 다른 것이 드문 일이 아닙니까? 또한 구현에서처럼 보이는 경우와 같은 #define XOR(ll,rr) { ll ? !rr : rr }호출 int x = 2; XOR(++x > 1, x < 5);은 잘못된 결과를 제공 한다는 의견에서 주목할 가치가 있습니다. 호출 int x = 2; XOR( (++x > 1), (x < 5) );에 올바른 예상 결과를 제공 하려면와 같이 추가 괄호가 있어야합니다 .
RA

1
XOR은 단락 될 수 없으므로 시퀀스 포인트가 필요하지 않습니다. XOR은 그 점에서 +와 비슷합니다. (++ x) + x가 2x + 1과 같다고 주장하지 않는 한 시퀀스 포인트는 합리적이지 않습니다.
hkBst

1
@ hkBst : 나는 이것이 내 대답의 두 번째 부분에 완전히 포함되어 있다고 생각합니다.
AnT

25

XOR을 수행하는 다른 방법이 있습니다.

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

다음을 통해 분명히 작동 할 수 있습니다.

#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;
}

7
이 접근법은 libstdc ++를 사용하여 clang과 gcc에서 (! a)! = (! b)보다 3-5 배 더 느린 느린 코드를 생성 할 수 있습니다. quick-bench.com/xtv2StFkR8PCkV4fOiqSgeG1T4Q
xaxxon

18

XOR 연산자는 단락 될 수 없습니다. 즉, 왼쪽 피연산자를 평가하여 XOR 표현식의 결과를 예측할 수 없습니다. 따라서 ^^버전 을 제공 할 이유가 없습니다 .


25
&&와 &의 주요 차이점은 단락이 아니기 때문에 -1입니다. 1 && 2는 True이지만 1 & 2는 false입니다. 단락은 편리한 부작용입니다.
Brian Postow

6
대답은 얘기하지 않습니다 &&&전혀. 요점은 소개 할 이유가 없다는 것입니다 ^^. ^^null 1이 아닌 값을 실제로 유용하지 않은 것으로 간주하는 속성은 의심합니다. 또는 적어도 나는 어떤 용도도 볼 수 없습니다.
Johannes Schaub-litb

6
또한 C ++! = 다른 언어들. 위에서 보여준 것처럼 C와 C ++에서 단락은 좋은 것만이 아니라 근본적으로 중요합니다. :)
Johannes Schaub-litb

13
그렇다면 왜 존재하지 않는지에 대한 Dennis Ritchie의 답변을 읽어야합니다. it.usyd.edu.au/~dasymond/mirror/c-faq/misc/xor.dmr.html
Johannes Schaub-litb

5
왜 존재하지 않는지에 대한 Dennis Ritchie의 답변에 대한 작업 링크는 다음과 같습니다. c-faq.com/misc/xor.dmr.html
Tobia

13

! a! =! b보다 문제를 더 잘 해결하는 좋은 코드가 게시되었습니다.

MSVC 2010에서 작동하도록 BOOL_DETAIL_OPEN / CLOSE를 추가해야합니다.

/* 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

6

간단한 것을 사용하십시오 :

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

5

다음은 C ++에서 XOR 비교를 작성하는 방법입니다.

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
}

증명

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

증거는 입력 및 출력에 대한 철저한 연구에서 두 테이블의 모든 입력 세트에 대해 결과가 항상 두 테이블에서 동일하다는 것을 보여줍니다.

따라서 원래 질문은 작성 방법입니다.

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

대답은

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

또는 원하는 경우 쓰기

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

! a! =! b는 당신의 주장을 당신을 위해 bool로 변환하기 때문에 더 좋을 것 같습니다.
xaxxon

3

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

첫 번째 부분은 A OR B이며 이는 포괄적 OR입니다. 두 번째 부분은 A와 B가 아닙니다. 함께 A 또는 B를 얻지 만 A와 B를 모두 얻지는 못합니다.

이것은 아래의 진리표에서 입증 된 XOR을 제공 할 것입니다.

|-----|-----|-----------|
|  A  |  B  |  A XOR B  |
|-----|-----|-----------|
|  T  |  T  |   False   |
|-----|-----|-----------|
|  T  |  F  |   True    |
|-----|-----|-----------|
|  F  |  T  |   True    |
|-----|-----|-----------|
|  F  |  F  |   False   |
|-----|-----|-----------|

나는이 접근법에 대한 성능을 파고 있지 않다 : quick-bench.com/PgNgGN8ATrKt7el1dAaJj7QtuF4
xaxxon

그것에 대해 방어적일 필요는 없습니다.
xaxxon

1
@xaxxon :이 벤치 마크에서 요점을 보지 마십시오!? StringCreation에서는 문자열을 만들 때 사용했지만 두 번째 벤치 마크에서는 그렇지 않았습니다. 두 벤치 마크에 동일한 코드를 배치하고 각 벤치 마크 (XOR 및 XOR2)마다 다른 XOR을 호출하면 동일한 벤치 마크 결과를 얻을 수 있습니다. 그래서 당신은 무엇을 말하려고 했습니까?
SoLaR

1

나는 "xor"를 사용한다. ( "키워드", Code :: Blocks 에서는 적어도 굵게 표시된다.) 대신 "and"대신 &&"or"를 사용할 수있다 ||.

if (first xor second)...

예, 비트 단위입니다. 죄송합니다.


2
나는 그것들이 어딘가에서 숨겨져 있다고 추측하고 있습니다. 나는 (적어도하지 C79) ... 그리고 "XOR은"ANSI C 키워드없는 확신 "와"
브라이언 Postow

1
@ 브라이언 Postow : 나는 C79이 무엇인지 알고 있지만, C ++ 98에없는 andxor표준 라이브러리 매크로입니다. Thay는 "어딘가"에서 온 것이 아니라 <iso646.h>에서 온 것입니다. 이 매크로는 C99에도 있습니다 (C89 / 90에 대해서는 확실하지 않음).
AnT

5
@ 브라이언 Postow는 ... xor의미 비트 동안,하지만 배타적 and논리 와.
AnT

1
C89로 C89를 잘못 입력했으며 xor 등이 K & R 사본에 없습니다. 난 당신이 바로 그 곳이 B-입니다 알고 일, 나는 적어도하지 고의로 ... 그래서, 그래, 그들이 어디에서 # 정의하고, 지금까지 사용 iso686.h을했습니다 생각하지 않는다)
브라이언 Postow

2
그들은 확실히 C99에 해당 헤더를 사용하고 있습니다. C ++에서는이 언어가 "대체 토큰"으로 언어에 통합되어 있으며 struct A { compl A() { } };예를 들어 소멸자를 정의 할 수 있습니다 .
Johannes Schaub-litb

0
#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);
}

정의 된대로 작동합니다. 조건은 bool 대신 BOOL을 요청하는 Objective-C 사용 여부를 감지하는 것입니다 (길이가 다릅니다!)


3
이것은 이중 밑줄 규칙을 위반합니다.
Tamás Szelei

@ TamásSzelei 컴파일러가 전처리 과정에서 사라진 것을 볼 필요는 없으며 Objective-C에서는 이중 밑줄이 상당히 일반적입니다.
Maxthon Chan

전처리기에 대한 좋은 지적은 나에게도 여전히 이런 식으로 코드 냄새가납니다 (어쨌든 매크로를 typedef 대신 사용합니까?). 또한 문제는 Objective-C에 관한 것이 아닙니다.
Tamás Szelei

@ TamásSzelei 글쎄, 나는 여러 언어로 헤더 파일을 공유하는 습관을 가지고 있었고 일반적으로 모든 헤더는 Objective-C에서 나왔습니다. 내 새 코드는 지금 너무 냄새가 나지 않지만 ObjC 습관을 지키기 위해 때때로 이중 밑줄이 사용됩니다.
Maxthon Chan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.