C ++ mantıksal XOR operatörü?


292

Böyle bir şey var mı? İlk kez pratik bir ihtiyaçla karşılaştım, ancak Stroustrup'ta listelenen birini göremiyorum . Yazmayı düşünüyorum:

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

Ama ^^operatör yok . ^Burada bitsel olarak kullanabilir ve doğru cevabı alabilir miyim (doğru ve yanlışın makine temsilinden bağımsız olarak)? Asla karıştırmam &ve &&ya da |ve ||bu yüzden ^ve ile yapmaktan çekinmeyin ^^.

Onun bool XOR(bool,bool)yerine kendi fonksiyonumu yazmakta daha rahat olurdum .


57
Aslında Jim, & & && arasındaki tek fark bu değil, örneğin ... 1 && True. ama 1 & 2 => 0. Bu nedenle, "kısa devre" nin sadece sahip oldukları bir özellik olduğunu düşünüyorum. Mantıksal daha önemli bir özelliktir ...
Brian Postow

6
2 && 3 == true, ancak 2 & 3 == 2'den bahsetmiyorum bile
David Thornley

1
David Thomley: Evet, ama 2 ==> doğru, bu yüzden sorun yok ... Unutma, gerçekten
boolean yok

13
@BrianPostow: Aslında, C ++ 'da vardır.
Adrian Willenbücher

7
Aşağıda yayınlandığı gibi, Dennis Ritchie'nin neden var olmadığına dair cevabı: c-faq.com/misc/xor.dmr.html
Tobia

Yanıtlar:


536

!=Operatör için bu amaca hizmet booldeğerler.


7
Ama yanlış! = Yanlış => yanlış
Jonas

13
Bunun sadece booleanlar için çalıştığını unutmayın. Ve ^ orada mükemmel çalışır. 2! = 1 => 1 ki istediğin bu değil! LiraNuna'nın dediği gibi, koyarak! her iki tarafın da önünde bu sorunu çözer. ama yine, o zaman bitsel kullanabilirsiniz ^ ...
Brian Postow

8
Doğru, " booldeğerler için" bahsetmeye dikkat ettim çünkü boolean olmayanlar için ne istersen yapmaz. Ve bu C ++ olduğundan, bu amaç booliçin kullanmak yerine gerçek bir tür vardır int.
Greg Hewgill

29
aSadece yazmak için yazmak istiyorsanız!(a) != !(a)
Chris Lutz

6
@ChrisLutz: evet, ancak aşırı yüklenmiş operatörlere dikkat edin.
rwong

246

Gerçek bir mantıksal XOR işlemi için bu işe yarayacaktır:

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

Not !İki eşitsiz pozitif tamsayılar (her bir böylece, boolelerde değerleri vardır dönüştürmek ve onları etkisiz hale true) için değerlendirirsiniz false.


6
A ve B'nin neden reddedildiğini anlamıyorum!
Martin Hansen

26
Temelde onları boole dönüştürmek. !!sadece iyi sormak, ama farklı olmaları gerektiğinden, onları reddetmek zarar vermez.
LiraNuna

4
Soru, derleyiciler bunu uygun şekilde optimize edebiliyor mu?
einpoklum

6
Boolleri normalleştirmenin önemini bilmemek 2 güne mal oldu.
Makan Tayebi

9
@LiraNuna, "A ve B neden reddedildi!" / "Temelde onları boole dönüştürmek." - Bence bu cevapta değinmeye değer.
cp.engr

42

Uygun manuel mantıksal XOR uygulaması, diğer mantıksal operatörlerin ( ||ve &&) XOR'nuzla genel davranışını ne kadar taklit etmek istediğinize bağlıdır . Bu operatörler hakkında iki önemli şey vardır: 1) kısa devre değerlendirmesini garanti ederler, 2) bir dizi noktası eklerler, 3) işlenenlerini yalnızca bir kez değerlendirirler.

Anladığınız gibi XOR değerlendirmesi kısa devre yapılamaz çünkü sonuç her zaman her iki işlenene de bağlıdır. Yani 1 söz konusu değil. Peki ya 2? 2'yi umursamıyorsanız, normalleştirilmiş (yani bool) değerlerle operatör !=XOR'un işini sonuç olarak yapar. Ve işlenenler !gerekirse tekli ile kolayca normalleştirilebilir . Böylece !A != !Bbu konuda uygun XOR'u uygular.

Ancak, ekstra dizi noktasını önemsiyorsanız, !=XOR'u ^uygulamak için uygun yol ne de bitsel değildir . XOR (a, b) 'yi doğru yapmanın olası bir yolu aşağıdaki gibi görünebilir

a ? !b : b

Bu "benzer" bir ev yapımı XOR yapmaya alabilirsiniz kadar yakın aslında ||ve &&. Bu, elbette, yalnızca XOR'nuzu bir makro olarak uygularsanız çalışır. Sıralama işlevi işlevin bağımsız değişkenlerine uygulanmayacağından işlev çalışmaz.

Birisi her bir sekans noktası olmasının tek nedeni bu olsa diyebilirsiniz &&ve ||bir kısa devre değerlendirmesini destekleyen ve böylece XOR birini gerekmez. Bu aslında mantıklı. Yine de, ortada bir sekans noktası olan bir XOR'a sahip olmayı düşünmeye değer. Örneğin, aşağıdaki ifade

++x > 1 && x < 5

(en az sekanslama ile ilgili olarak) C / C ++ 'da davranış ve spesifik sonuç tanımlamıştır. Dolayısıyla, kullanıcı tanımlı mantıksal XOR'dan aynı şekilde makul bir şekilde beklenebilir .

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

Bir süre !=tabanlı XOR bu özelliği yoktur.


1
Diğer önemli şeyleri kaçırıyorsunuz ||ve &&: C) işlenenleri boole bağlamında değerlendiriyorlar. Yani, 1 && 2doğrudur, aksine 1 & 2sıfırdır. Benzer şekilde, bir ^^operatör, işlenenleri bir boole bağlamında değerlendirmek için bu ekstra özelliği sağlamak için yararlı olabilir. Örneğin 1 ^^ 2yanlıştır (aksine 1 ^ 2).
Craig McQueen

2
@Craig McQueen: Ben özlemiyorum. Yazımın ikinci paragrafında bundan bahsediliyor. Kanımca, işlenenlere boole değerleri olarak davranmak, mantıksal işleçlerin kritik bir özelliği değildir, bir anlamda, yalnızca bu nedenle kullanılmayacaklardır. Başlatılmalarının ana nedeni kısa devreli değerlendirme ve bunun için gerekli sıralama noktasıdır.
AnT

Bugünlerde öneriniz hala sadece bir makro ile çalışır mı? Bir fonksiyonda değerlendirilecek parametre sırasının derleyiciye bağlı olduğu doğru olsa da, şu anda soldan sağa farklılık göstermesi nadir değildir? Ayrıca, burada bir uygulama benziyorsa, böyle #define XOR(ll,rr) { ll ? !rr : rr }bir çağrının int x = 2; XOR(++x > 1, x < 5);yanlış sonuç vereceğini yorumlarda belirtmek gerekir . int x = 2; XOR( (++x > 1), (x < 5) );Beklenen doğru sonucu verebilmek için çağrıda olduğu gibi ekstra parantez olması gerekir .
RAs

1
XOR kısa devre yapamadığından, bir dizi noktasına gerek yoktur. XOR bu açıdan + 'ya benzer. Ayrıca (++ x) + x'in 2x + 1'e eşit olduğunu iddia etmek istemiyorsanız, sıralama noktası makul değildir.
hkBst

1
@hkBst: Bunun cevabımın ikinci bölümünde tamamen ele alındığını düşünüyorum.
AnT

25

XOR yapmanın başka bir yolu var:

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

Hangi açıkça çalışmak için kanıtlanabilir:

#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
Bu yaklaşım bazı oldukça yavaş kodu oluşturabilirsiniz - daha yavaş 3-5x (! A) = ++ libstdc kullanarak clang ve gcc hem tarih:! (B!) Quick-bench.com/xtv2StFkR8PCkV4fOiqSgeG1T4Q
xaxxon

18

XOR operatörü kısa devre yapamaz; yani bir XOR ifadesinin sonucunu sadece sol tarafındaki işleneni değerlendirerek tahmin edemezsiniz. Dolayısıyla, bir ^^sürüm sağlamak için hiçbir neden yoktur .


25
-1 çünkü && ve & arasındaki temel fark sadece kısa devre değildir. 1 && 2 doğrudur, ancak 1 & 2 yanlıştır. Kısa devre sadece kullanışlı bir yan etkidir.
Brian Postow

6
Cevap, hiç &&ve &hiç bahsetmiyor . Amacı, tanıtmak için bir neden olmadığıdır ^^. Mülkiyet ^^gibi herhangi boş olmayan bir değer kabul ediyorum 1gerçekten yararlı değildir, ben şüpheli. Ya da en azından bir fayda göremiyorum.
Johannes Schaub - litb

6
Ayrıca C ++! = Diğer diller. Yukarıda gösterildiği gibi C ve C ++ 'da kısa devre sadece bazı hoş şeyler değil, aynı zamanda temelde önemlidir. :)
Johannes Schaub - litb

13
Öyleyse Dennis Ritchie'nin neden var olmadığına dair cevabını okumalısınız: it.usyd.edu.au/~dasymond/mirror/c-faq/misc/xor.dmr.html
Johannes Schaub - litb

5
İşte Dennis Ritchie'nin neden var olmadığına dair cevabı üzerinde çalışan bir bağlantı: c-faq.com/misc/xor.dmr.html
Tobia

13

Sorunu daha iyi çözen bazı iyi kodlar vardı! A! =! B

MSVC 2010 üzerinde çalışması için BOOL_DETAIL_OPEN / CLOSE eklemem gerektiğini unutmayın

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

Basit kullanın:

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

5

İşte nasıl C ++ XOR karşılaştırma yazmak düşünüyorum:

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
}

Kanıt

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

Kanıt, girdi ve çıktıların kapsamlı bir çalışmasının, iki tabloda, her girdi seti için sonucun her iki tabloda da aynı olduğunu gösterdiğidir.

Bu nedenle, orijinal soru nasıl yazılacağıdır:

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

Cevap şu olurdu:

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

İsterseniz yazın

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

! a! =! b daha hoş görünüyor çünkü argümanlarınızı sizin için boole dönüştürüyor.
xaxxon

3

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

İlk bölüm, Kapsayıcı VEYA olan A OR B'dir; ikinci kısım, A VE B DEĞİLDİR. Birlikte A veya B alırsınız, ancak hem A hem de B elde edemezsiniz.

Bu, aşağıdaki doğruluk tablosunda kanıtlanmış XOR'u sağlayacaktır.

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

Bu yaklaşımdaki performansı kazmıyorum
xaxxon

Bu konuda savunmaya gerek yok.
xaxxon

1
@xaxxon: Bu kriterlerde konuyu anlamıyorum !? StringCreation'da dize oluştururken kullandınız, ancak ikinci karşılaştırmada kullanmadınız. Her iki ölçütte de aynı kodu yerleştirirseniz ve her bir karşılaştırmalı değerlendirme için farklı XOR'leri (XOR ve XOR2) çağırırsanız, aynı karşılaştırmalı değerlendirme sonuçları elde edersiniz. Ne demeye çalışıyorsun?
SoLaR

1

"Xor" kullanıyorum (bir anahtar kelime gibi görünüyor; Code :: Blocks'ta en azından kalınlaşıyor) tıpkı "ve" yerine &&ve "veya" yerine kullanabileceğiniz gibi ||.

if (first xor second)...

Evet, bitsel. Afedersiniz.


2
Bunların bir yerden gizli # tanımlamalar olduğunu tahmin ediyorum. Eminim "ve" ve "xor" ansi C'deki anahtar kelimeler değildir ... (en azından C79 değil)
Brian Postow

1
@Brian Postow: C79'un ne olduğunu bilmiyorum, ama C ++ 98'de andve xorstandart kütüphane makroları. Thay "bir yerden" değil, <iso646.h> 'dan. Bu makrolar da C99'dadır (C89 / 90 hakkında emin değilim).
AnT

5
@Brian Postow: ... ama bitsel xor xoranlamına gelirken , mantıklı ve. and
AnT

1
C89'u C79 olarak yanlış yazdım ... ve xor vb K & R kopyamda değil. Hiç iso686.h kullandığımı sanmıyorum, en azından bilerek değil ... ve bu yüzden, evet, onlar bir yerden # tanımlı, sadece bir yerde B- nerede olduğunu biliyorsunuz)
Brian Postow

2
Kesinlikle C99'da bu başlığı kullanıyorlar. C ++ 'da dile "alternatif jetonlar" olarak entegre edilmiştir ve struct A { compl A() { } };örneğin bir yıkıcı tanımlayabilirsiniz.
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);
}

Tanımlandığı gibi çalışır. Koşullar, bool yerine BOOL isteyen Objective-C kullanıp kullanmadığınızı tespit etmektir (uzunluk farklıdır!)


3
Bu, çift alt çizgi kuralını ihlal eder.
Tamás Szelei

@ TamásSzelei Derleyicinin ön işleme koyduğu ve Objective-C dünyasında çift alt çizgilerin oldukça yaygın olduğunu görmesi gerekmez.
Maxthon Chan

Önişlemci hakkında iyi bir nokta, bana rağmen hala bu şekilde kod kokusu (yine de bir typedef yerine bir makro kullanalım?). Ayrıca, soru Objective-C ile ilgili değildi.
Tamás Szelei

@ TamásSzelei Pek çok dilde başlık dosyalarını paylaşma alışkanlığım vardı ve genellikle tüm başlıklar Objective-C'den geliyor. Yeni kodum şu anda çok fazla kokmuyor, ancak çift alt çizgi ObjC alışkanlıklarına uymak için zaman zaman hala kullanılıyor.
Maxthon Chan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.