Warunkowe XOR?

89

Dlaczego C # nie ma XORoperatora warunkowego ?

Przykład:

true  xor false = true
true  xor true  = false
false xor false = false
Gilad Naaman
źródło
15
Jak !=działa jako substytut?
Pascal Cuoq
45
C # nie mają operatora XOR (x ^ Y). Dlatego zaprzeczam przesłance pytania. Czy możesz wyjaśnić, dlaczego uważasz, że C # nie ma operatora xor? Jestem zainteresowany, aby dowiedzieć się, dlaczego ludzie wierzą w fałszywe rzeczy o C #.
Eric Lippert
3
@Eric Lippert: Myślę, że odnosi się do operatorów logicznych ( & | ^) kontra operatory warunkowe ( && ||). Ale masz rację (oczywiście), istnieje logiczna XOR ...
BoltClock
14
@BoltClock: Och, jeśli pytanie brzmi "dlaczego nie ma zwierającego operatora xor?" - jak to możliwe? Z „i”, jeśli pierwszy argument jest fałszywy, nie musisz oceniać drugiego. Z „lub”, jeśli pierwszy argument jest prawdziwy, nie musisz oceniać drugiego. Zawsze musisz ocenić oba argumenty dla xor, więc nie ma możliwości zwarcia.
Eric Lippert
4
Samo pytanie jest bardziej odpowiednie dla Microsoftu - a więc jest to przyzwoity powód, aby głosować przeciw - ale jeśli ktokolwiek przegłosował, zrobił to z powodu operatora ^, to musisz przeczytać z większą dbałością o szczegóły, ponieważ pytanie było warunkowe vs. logiczne, a nie tylko „dlaczego nie ma XOR”.
The Evil Greebo

Odpowiedzi:

124

W języku C # operatory warunkowe wykonują swój pomocniczy operand tylko w razie potrzeby .

Ponieważ XOR musi z definicji testować obie wartości, wersja warunkowa byłaby głupia.

Przykłady :

  • Logiczne AND: &- testuje za każdym razem obie strony.

  • Logiczne LUB: |- za każdym razem testuj obie strony.

  • I warunkowe: &&- testuje drugą stronę tylko wtedy, gdy pierwsza jest prawdziwa.

  • Warunkowe LUB: ||- testuj drugą stronę tylko wtedy, gdy pierwsza strona jest fałszywa.

Zły Greebo
źródło
37
Operator XOR nie naruszy konwencji „operatory warunkowe wykonują swój dodatkowy argument tylko wtedy, gdy jest to konieczne”. To byłoby po prostu zawsze konieczne.
Nathan Kovner
2
Warunkowy XOR może być ładnym i eleganckim skrótem dla niektórych określonych wzorców, chociaż nie jest pewien, czy jest wystarczająco uzasadniony, aby włączyć go do języka. Przykładem takich wzorców, w których XOR może się okazać przydatny, jest Negacja warunkowa: Kiedy wyrażenie boolowskie powinno zostać zanegowane lub nie, przy podaniu drugiego wyrażenia boolowskiego.
SalvadorGomez
1
Od jakiegoś czasu nie odpowiadałem na to, ale odpowiadając na popularny komentarz @KhyadHalda: Dlaczego miałbyś kiedykolwiek zbudować coś, o czym wiesz, że nigdy nie zostanie użyte? Będziesz celowo pisać martwy kod.
The Evil Greebo
2
Jak kiedykolwiek warunkowy XOR byłby kiedykolwiek przydatny? Warunkowe XOR nie może kiedykolwiek ocenić bez porównania obu stron w celu ustalenia, czy są one równe, czy też nie. Nawet koncepcja warunkowego XOR porównującego dwa boole musi nadal sprawdzać wartość każdego bool i testować równość.
The Evil Greebo
1
Jest tak głupi, jak operator dodawania warunkowego. Dlaczego nie utworzyć innego operatora do dodawania warunkowego, gdzie (a + b) oblicza b tylko wtedy, gdy b jest konieczne? Podobnie jak w przypadku warunkowego XOR, nie naruszyłoby to konwencji operatorów warunkowych, po prostu drugi argument byłby zawsze potrzebny. Nie ma żadnego zastosowania tego nigdy. I nie jestem tylko pedantyczny w tym przykładzie - operacja XOR jest zasadniczo 1-bitowym dodatkiem.
Kevin Holt
283

Pytanie jest nieco przestarzałe, ale ...

Tak powinien działać ten operator:

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

Oto jak! = Operator działa z typami bool:

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

Więc jak widzisz, nieistniejący ^^może zostać zastąpiony istniejącym!=

piotrpo
źródło
46
W rzeczywistości jest to jedyna odpowiedź, która bezpośrednio i poprawnie odpowiada na to pytanie.
usr
40
Siedzę tutaj, udając, że nie zdawałem sobie sprawy, !=że to zadziała.
AdamMc331
1
Odpowiedź jest prawidłowa, ale komentarze nie. Nie odpowiada na pytanie „dlaczego C # nie ma warunkowego XOR?”. Ściśle mówiąc, to nie jest operator logiczny, to operator równości relacji. Chociaż wynik jest taki sam jak XOR, to jest w innej klasie. Porównuje się z XOR tylko podczas testowania dwóch wartości logicznych, a obie strony operatora nadal muszą zostać ocenione.
The Evil Greebo
3
@TheEvilGreebo - To, co mówisz, jest prawdą; operator! = nie jest technicznie operatorem warunkowym XOR. Jednak ta odpowiedź skutecznie mówi: „Operator warunkowy XOR nie istnieje, ponieważ istnieje operator! =”. W każdym razie tak to przeczytałem.
Syndog
6
Myślę, że prawie każdy trafił do tego posta i chciał napisać XOR na Booleans. jakby to było logiczne ANDi ORale nic jak XOR. a przynajmniej nie zdawaliśmy sobie sprawy !=:) @TheEvilGreebo
M.kazem Akhgary
30

Istnieje logiczny operator XOR: ^

Dokumentacja: Operatory C # i ^ Operator

iceaway
źródło
2
Logiczne, nie warunkowe. Logiczne i = &, warunkowe i = &&. Pyta o warunkowe.
The Evil Greebo
3
Jest binarny, a nie logiczny. Zakłada, że ​​bools mają wartość 0 lub 1, co nie jest prawdą w CLR.
usr
1
przepraszam, ta odpowiedź tak naprawdę nie odpowiada na pytanie dotyczące operatorów WARUNKOWYCH. to trochę opperator
Nathan Tregillus
3
Dla przypomnienia, dokumentacja, do której link znajduje się w tej odpowiedzi, wyraźnie stwierdza, że ^w przypadku użycia z operandami boolowskimi jest operatorem boolowskim. "dla operandów bool, operator ^ oblicza ten sam wynik, co operator nierówności! =". Możesz także bitwise-xor integer operandy z ^. C # nie jest C.
15ee8f99-57ff-4f92-890c-b56153
25

Dla wyjaśnienia, operator ^ działa zarówno z typami całkowitymi, jak i logicznymi.

Zobacz ^ Operator MSDN (odwołanie w C #) :

Operatory binarne ^ są wstępnie zdefiniowane dla typów całkowitych i bool. W przypadku typów całkowitych ^ oblicza bitowy OR na wyłączność swoich operandów. Dla operandów bool, ^ oblicza logiczne wyłączne-lub swoich operandów; to znaczy, wynik jest prawdziwy wtedy i tylko wtedy, gdy dokładnie jeden z jego argumentów jest prawdziwy.

Być może dokumentacja zmieniła się od 2011 roku, kiedy zadano to pytanie.

RichardCL
źródło
2
programowałem w języku c # od dawna, nigdy o tym nie wiedziałem! dzięki @RichardCL!
Nathan Tregillus,
Jest to dobra informacja, ale wydaje się bardziej odpowiednia jako komentarz lub poprawka do innej odpowiedzi, która wspomina tę odpowiedź ^i jest o pięć lat wcześniejsza. Wątpię, żeby coś się zmieniło.
Chris
13

Zgodnie z zapytaniem Marka L. Oto poprawna wersja:

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

Oto tabela prawdy:

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

Odniesienie: ekskluzywny OR

Simple Fellow
źródło
2
Zadane pytanie brzmiało: DLACZEGO C # nie ma warunkowego operatora XOR. To nie odpowiada na pytanie. Jeśli chodzi o samą funkcję: ta funkcja działa jako warunkowy XOR - jednak pytanie brzmi, czy jest bardziej wydajny niż bezwarunkowy XOR? Aby sprawdzić, czy jest prawdą, XOR musi potwierdzić, że jeden i dokładnie jeden wynik jest prawdziwy. Oznacza to, że obie strony muszą zostać ocenione i porównane. Powyższa funkcja testuje obie strony warunku i, jednocześnie odwracając co najmniej jedną wartość. Czy wiemy wewnętrznie, czy różni się to od XOR?
The Evil Greebo
6

O tak, to prawda.

bool b1 = true;
bool b2 = false;
bool XOR = b1 ^ b2;
Armen Tsirunyan
źródło
1
Jest to operator binarny, a nie logiczny. Zakłada, że ​​bools mają wartość 0 lub 1, co nie jest prawdą w CLR. Więc ten kod może faktycznie nie działać.
usr
6
@usr, w C #, operator ^ jest logiczny, gdy jest stosowany do dwóch operandów boolowskich. Bardzo dużo skomentowałeś poprzez te odpowiedzi, czy kiedykolwiek uruchomiłeś jakiś kod, aby sprawdzić swoją hipotezę?
Marc L.
2
@MarcL. Zrobiłem: pastebin.com/U7vqpn6G Wyświetla true, chociaż true ^ true ma być fałszywe. bool nie zawsze jest równe 0 lub 1. Nie jest to typ logiczny w środowisku CLR. Jest to wielkość 8-bitowa z dowolną zawartością. Mogłem również wygenerować weryfikowalny IL, aby zademonstrować problem.
usr
2
Na przykład w przypadku korzystania z innych języków CLR niż C #. Powtarzam: mogłem użyć ILASM do stworzenia w pełni weryfikowalnego, bezpiecznego zestawu, który to robi (na poziomie IL wartość boolowska to po prostu an i1, tak jak bajt). Jest to w 100% zdefiniowane i bezpieczne zarządzane zachowanie. CLR nie jest nierówny .; Po raz pierwszy zobaczyłem to zachowanie podczas korzystania z Microsoft Pex.
usr
1
@EdPlunkett, nie sądzę, żeby twoja ciężarówka była ze mną. usr pokazał, że wewnętrznie jest to operator binarny . „Nadużycie”, na które się skarżyłem, było sposobem, w jaki to udowodnił, a który nadal uważam za zbyt ostry. Może się tak zdarzyć, ale tak dokładnie przenosi użycie Boolean na ziemię niczyją, że wdrożenie go jako bezpiecznego dla CLR byłoby w najlepszym przypadku niebezpieczne, aw najgorszym obraźliwe (jeśli nie złośliwe) i powinno być traktowane jako błąd. Usr udowadnia, że ​​wewnętrznie C # jest bardziej podobny do C niż ktokolwiek z nas sądził. Kolejną kwestią jest to, czy kod, który to robi, należy uznać za ważny.
Marc L.
4

Warunkowe xor nie istnieje, ale możesz użyć logicznego, ponieważ xor jest zdefiniowany dla wartości logicznych, a wszystkie porównania warunkowe są obliczane na wartości logiczne.

Możesz więc powiedzieć coś takiego:

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

}
Klark
źródło
Jest to operator binarny, a nie logiczny. Zakłada, że ​​bools mają wartość 0 lub 1, co nie jest prawdą w CLR. Więc ten kod może faktycznie nie działać.
usr
@usr co masz na myśli, CLR? To zadziałało dla mnie, nie jestem pewien, czy przegapiłem przypadek krawędzi tutaj ...
LunaCodeGirl
3
@Spencevail prawdopodobnie nie myślałeś o przypadku, w którym niefałszowa wartość logiczna może nie mieć reprezentacji całkowitej 1. To mało znany fakt. Możesz skończyć w sytuacji, w której xor dwóch niefałszowanych wartości logicznych nadal nie jest fałszywy! To powiedziawszy w tym konkretnym kodzie, operator xor jest zawsze stosowany tylko do wartości w [0,1], więc mój komentarz nie ma (w pełni) zastosowania.
usr
1
@Spencevail to jest dokładnie przypadek, który może się nie udać. Możliwe jest utworzenie bezpiecznej funkcji kodu zarządzanego CreateBool (bajt), która konwertuje bajt na bool o tych samych bitach. Następnie CreateBool (1) ^ CreateBool (2) ma wartość true, ale CreateBool (1) ma wartość true i CreateBool (2) również jest prawdziwe! &jest również wrażliwy.
usr
1
Właściwie właśnie zgłosiłem błąd RyuJIT, ponieważ nie rozważali tej możliwości i skompilowali &&tak, jakby to była &błędna kompilacja.
usr
3

Chociaż istnieje logiczny operator xor ^, nie ma warunkowego operatora xor. Możesz uzyskać warunkowy xor dwóch wartości A i B za pomocą:

A ? (!B) : B

Pareny nie są konieczne, ale dodałem je dla jasności.

Jak wskazał The Evil Greebo, oblicza to oba wyrażenia, ale xor nie może być zwarty jak i i lub .

jimreed
źródło
Jaka jest różnica między logikanem ^ a warunkowym ^? oO
Armen Tsirunyan
@Armen Tsirunyan Operatory logiczne wykonują operacje bitowe w typach, w których ma to sens, podczas gdy operatory warunkowe działają na wartościach logicznych i zwracają wynik boolowski. Biorąc pod uwagę wartości logiczne: 0101 ^ 0011ma wartość 0110.
jimreed
3
nie, całkowicie się mylisz. istnieją oba typy XOR (nazywane są odpowiednio bitowe i logiczne) w C #. Oba używają symbolu ^.
Armen Tsirunyan
1

możesz użyć:

a = b ^ c;

tak jak w c / c ++

gulyan
źródło
0

Nie ma czegoś takiego jak warunkowy (zwierający) XOR. Operatory warunkowe mają znaczenie tylko wtedy, gdy istnieje sposób na ostateczne określenie wyniku końcowego, patrząc tylko na pierwszy argument. XOR (i dodawanie) zawsze wymaga dwóch argumentów, więc nie ma możliwości zwarcia po pierwszym argumencie.

Jeśli wiesz, że A = prawda, to (A XOR B) =! B.

Jeśli wiesz, że A = fałsz, to (A XOR B) = B.

W obu przypadkach, jeśli znasz A, ale nie znasz B, to nie wiesz wystarczająco dużo, aby wiedzieć (A XOR B). Aby obliczyć odpowiedź, zawsze musisz poznać wartości A i B. Nie ma dosłownie żadnego przypadku użycia, w którym można by kiedykolwiek rozwiązać XOR bez obu wartości.

Pamiętaj, że XOR z definicji ma cztery przypadki:

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

Miejmy nadzieję, że z powyższego jasno wynika, że ​​znajomość pierwszej wartości nigdy nie wystarczy, aby uzyskać odpowiedź bez znajomości drugiej wartości. Jednak w swoim pytaniu pominąłeś pierwszy przypadek. Jeśli zamiast tego chciałeś

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

wtedy rzeczywiście możesz to uzyskać poprzez zwieranie operacji warunkowej:

A && !B

Ale to nie jest XOR.

Kevin Holt
źródło
W tej odpowiedzi nie widzę niczego, czego nie ma w co najmniej jednej odpowiedzi powyżej. Nie widzę żadnych wskazań, że OP szukał twojego powodującego zwarcia un-xora, ponieważ przyjął odpowiedź, która zakłada, że ​​chciał właściwego xor.
15ee8f99-57ff-4f92-890c-b56153
Moja jest dosłownie jedyną odpowiedzią sugerowaną do tej pory, która może wygenerować żądaną przez PO tabelę prawdy bez oceny drugiego argumentu.
Kevin Holt
Również OP zapytał, dlaczego nie ma warunkowego XOR, i chociaż powyższe odpowiedzi mówią poprawnie, że dzieje się tak dlatego, że XOR wymaga dwóch argumentów, IMO wydaje się, że powyższe odpowiedzi nie mówią wystarczająco jasno, DLACZEGO XOR faktycznie potrzebuje dwóch argumentów. Oczywiście czujesz inaczej, ale dla mnie było oczywiste z różnych komentarzy na tej stronie, że podstawowa dwuargumentowość XOR nie została jeszcze w pełni wyjaśniona całkowicie początkującym.
Kevin Holt
1
Namówiłeś mnie do tego.
15ee8f99-57ff-4f92-890c-b56153
@Kevin Holt - Logiczny XOR ma znaczenie, jeśli potrzebujesz, aby jeden z warunków był spełniony, ale nie oba. To, że musisz ocenić oba warunki, nie ma znaczenia. Zwarcie jest szczegółem niskiego poziomu, o który musisz się martwić tylko w przypadku kodu krytycznego dla wydajności (przepływ sterowania jest powolny). Bardziej interesowałbym się tym, co ma oznaczać „wyłączność”, kiedy robię z tego operator logiczny. Mianowicie, niech działa jak wersja bitowa (jak inne operatory) lub uczyń ją wyłączną lub (tyle warunków, ile chcesz, ale tylko jeden może być prawdziwy).
Thorham
-3

Na to pytanie udzielono pozytywnej odpowiedzi, ale trafiłem na inną sytuację. Prawdą jest, że nie ma potrzeby warunkowego XOR. Prawdą jest również, że można użyć operatora ^. Jeśli jednak potrzebujesz tylko przetestować stan argumentów „prawda || fałsz”, wtedy ^ może spowodować problemy. Na przykład:

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

W tym przykładzie, jeśli left jest ustawione na 10 (0xa), a prawe jest ustawione na 5 (0x5), wprowadzana jest gałąź „Success”. W tym (prostym, choć głupim) przykładzie spowodowałoby to błąd, ponieważ nie należy jednocześnie skręcać w lewo ORAZ w prawo. To, co otrzymałem od pytającego, to nie to, że faktycznie chciał warunkowej, ale prosty sposób na wykonanie prawdy / fałszu na wartościach przekazanych do xor.

Makro może załatwić sprawę:

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

Możesz mnie spoliczkować, jeśli nie mam racji: o)

Przeczytałem odpowiedź jimreeda poniżej po tym, jak to opublikowałem (zły Yapdog!), A jego jest właściwie prostszy. To by zadziałało i absolutnie nie mam pojęcia, dlaczego jego odpowiedź została odrzucona ...

Yap Dog
źródło
3
To jest pytanie C #, a nie C / C ++. ifwymaga wyrażenia logicznego, nie zostanie nawet skompilowany z wartością typu int.
Marc L.