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에없는 and및 xor표준 라이브러리 매크로입니다. 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.