有条件的XOR?


87

C#为什么没有条件XOR运算符?

例:

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

15
如何!=替代?
Pascal Cuoq

45
C#确实具有xor运算符(x ^ y)。因此,我否认这个问题的前提。您能解释一下为什么您认为C#没有xor运算符吗?我有兴趣了解为什么人们会相信有关C#的虚假信息。
埃里克·利珀特

3
@Eric Lippert:我认为他指的是逻辑运算符(& | ^)与条件运算符(&& ||)。但是您是对的(当然),这是合乎逻辑的XOR ...
BoltClock

14
@BoltClock:哦,如果问题是“为什么没有短路异或运算符?” -怎么会有?用“ and”表示,如果第一个参数为false,则无需评估第二个。使用“或”,如果第一个参数为true,则无需评估第二个。您始终需要为xor评估两个参数,因此不可能发生短路。
埃里克·利珀特

4
这个问题本身更适合Microsoft-因此,这是拒绝投票的一个正当理由-但是,如果由于^运算符而拒绝投票的人这样做,则您需要更加注意细节,因为该问题是有条件的。逻辑,而不仅仅是“为什么没有XOR”。
邪恶的Greebo,

Answers:


121

在C#中,条件运算符仅在必要时执行其辅助操作数。

由于按定义XOR必须同时测试两个值,因此条件版本会很愚蠢。

例子

  • 逻辑与:&-每次都测试双方。

  • 逻辑或:|-每次都测试双方。

  • 条件AND:&&-仅当第一面为真时才测试第二面。

  • 有条件的OR:||-如果第一面为假,则仅测试第二面。


35
XOR运算符不会违反约定“条件运算符仅在必要时执行其辅助操作数”。只是总是有必要的。
内森·科夫纳

2
对于某些特定模式,条件XOR可能是一个不错的,优雅的捷径,尽管不确定是否有足够的理由将其包括在语言中。条件否定:其中一种可能证明XOR有用的模式的例子:给定第二个布尔表达式时,是否应该否定布尔表达式。
SalvadorGomez

1
有一段时间没有对此作出回应,而是回应@KhyadHalda的热门评论:为什么您会构建自己知道永远不会使用的东西?您将故意编写无效代码。
邪恶的格力保(Evil Greebo)

考虑到条件XOR运算符不会违反您定义的约定(Khyad的评论),加上在某些情况下它实际上会有用的事实,它几乎抵消了您归因于此类运算符的任何“空洞”。
Syndog

1
有条件的XOR怎么会有用?有条件的异或运算永远无法进行评估,而无需比较双方以确定它们是否相等。甚至比较两个布尔的条件XOR的概念也必须检查每个布尔的值并测试其相等性。
邪恶的格里宝(

280

问题有点过时了,但是...

此运算符应如何工作:

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

这是!=运算符对布尔类型的工作方式:

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

如您所见,不存在的东西^^可以替换为现有的!=


46
实际上,这是直接,正确解决该问题的唯一答案。
usr

39
我坐在这里面无表情地自以为是,我没有意识到!=会为此工作。
AdamMc331

1
答案是正确的,但评论不正确。它没有解决这个问题,即“为什么C#没有条件XOR?”。严格来说,这不是逻辑运算符,而是关系相等运算符。虽然结果与XOR相同,但结果却不同。它仅在测试两个布尔值时才与XOR进行比较,并且仍然必须对运算符的两端进行求值。
邪恶的Greebo,2017年

3
@TheEvilGreebo-你说的是真的;!=运算符从技术上讲不是条件XOR运算符。但是,此答案有效地表明:“条件XOR运算符不存在,因为!=运算符确实存在。” 无论如何,这就是我的阅读方式。
Syndog

6
我认为几乎每个最终写这篇文章的人实际上都想对布尔值进行XOR。像有逻辑ANDOR,但毫无作为XOR。或至少我们没有意识到!=:) @TheEvilGreebo
M.kazem Akhgary

30

有逻辑XOR运算符: ^

文档:C#运算符^运算符


2
逻辑的,不是有条件的。逻辑与=&,条件与= &&。他在问有条件的。
邪恶的Greebo,

3
它是二进制的,不是逻辑的。它假定布尔值为0或1,这在CLR上不正确。
usr

1
抱歉,此答案实际上并未回答有关CONDITIONAL运算符的问题。这是位操作者
Nathan Tregillus

2
作为记录,此答案中链接的文档明确指出^,当与布尔操作数一起使用时,它是布尔运算符。“对于布尔操作数,^运算符计算的结果与不等式运算符!=“相同。您也可以使用进行按位异或整数操作数^。C#是不是C.
15ee8f99-57ff-4f92-890c-b56153

24

澄清一下,^运算符可用于整数类型和布尔型。

请参见MSDN的^运算符(C#参考)

预定义了整数类型和布尔值的二进制^运算符。对于整数类型,^计算其操作数的按位异或。对于布尔操作数,^计算其操作数的逻辑异或;也就是说,只有且仅当其操作数之一为真时,结果才为真。

自2011年提出此问题以来,文档可能已更改。


2
在C#中编程很久了,从来都不知道!谢谢@RichardCL!
内森·特雷格洛斯

这是很好的信息,但似乎更适合作为对另一个提到^并早于五年的答案的评论或编辑。我怀疑一切都没有改变。
克里斯

13

按照Mark L的要求,这是正确的版本:

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

这是事实表:

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

参考: 异或


2
问的问题是为什么C#没有条件XOR运算符。这不能回答问题。关于函数本身:此函数确实可以作为条件XOR进行操作-但是问题是,它比非条件XOR更有效吗?为了测试排他性事实,XOR必须确认一个且恰好一个结果为真。这意味着必须对双方进行评估和比较。上面的函数至少在反转一个值的同时测试an和condition的两侧。我们内部是否知道这与XOR有什么不同?
邪恶的格力保(Evil Greebo)

6

哦,是的。

bool b1 = true;
bool b2 = false;
bool XOR = b1 ^ b2;

1
它是二进制运算符,而不是逻辑运算符。它假定布尔值为0或1,这在CLR上不正确。因此,此代码实际上可能无法正常工作。
usr

6
@usr,在C#中,将^运算符应用于两个布尔操作数时是合乎逻辑的。您通过这些答案评论了很多,您是否曾经运行过任何代码来检验您的假设?
Marc L.

2
@马克 我做到了:pastebin.com/U7vqpn6G打印true,尽管true ^ true应该是假的。bool并不总是等于0或1。它不是CLR上的逻辑类型。它是一个8位的量,带有任意内容。我本可以生成可验证的IL来演示该问题。
usr

2
例如,当使用C#以外的其他CLR语言时。我重复一遍:我本可以使用ILASM创建一个完全可验证的安全程序集来执行此操作(在IL级别,布尔值只是一个i1,就像一个字节一样)。这是100%定义的安全行为。CLR尚未完善。我第一次看到这种行为是在使用Microsoft Pex时。
usr 2014年

1
@EdPlunkett,我认为您的卡车不在我身边。usr表明在内部它实际上是一个二进制运算符。我抱怨的“虐待”是他证明这一点的手段,我仍然认为这太过分了。可能会发生,但是将Boolean的使用如此广泛地用于无人之地,以至于将其部署为CLR安全型最好是危险的,最糟糕的是滥用(如果不是恶意的话),应将其视为错误。usr证明了C#在内部更像C,这比我们任何人都想像的要好。这样做的代码是否应被视为有效是另一个问题。
马克·L,

4

条件xor不存在,但是您可以使用逻辑1,因为xor是为布尔值定义的,并且所有条件比较的结果均为布尔值。

因此,您可以说类似以下内容:

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

}

它是二进制运算符,而不是逻辑运算符。它假定布尔值为0或1,这在CLR上不正确。因此,此代码实际上可能无法正常工作。
usr

@usr是什么意思CLR?这对我
有用

3
@Spencevail您可能没有考虑非假布尔值可能没有整数表示的情况1。这是一个鲜为人知的事实。您可能会遇到两个非虚假布尔值的xor仍然非虚假的情况!也就是说,在此特定代码中,xor运算符仅应用于[0,1]中的值,因此我的注释不(完全)适用。
usr

1
@Spencevail可能会失败。可以创建一个安全的托管代码函数CreateBool(byte),它将字节转换为相同位的布尔值。然后,CreateBool(1)^ CreateBool(2)为true,但是CreateBool(1)为true,CreateBool(2)也为true!&也很脆弱。
usr

1
实际上,我只是报告了一个RyuJIT错误,因为他们没有考虑这种可能性,&&因此将&其编译为错误编译。
usr

3

虽然存在逻辑异或运算符^,但没有条件异或运算符。您可以使用以下方法获得两个值A和B的条件异或:

A ? (!B) : B

括号不是必需的,但为清楚起见,我添加了它们。

正如The Evil Greebo指出的那样,这将对两个表达式求值,但是xor不能像andor那样短路。


逻辑^和条件^有什么区别?oO
Armen Tsirunyan

@Armen Tsirunyan逻辑运算符以有意义的类型执行按位运算,而条件运算符对布尔值进行运算并返回布尔结果。考虑布尔值:0101 ^ 0011具有值0110
jimreed 2011年

3
不,你完全错了。在C#中,有两种类型的XOR(分别称为按位和逻辑)。两者都使用^符号。
Armen Tsirunyan 2011年


0

没有条件(短路)XOR之类的东西。条件运算符仅在有办法通过仅查看第一个参数来明确告诉最终结果时才有意义。XOR(和加法)始终需要两个参数,因此在第一个参数之后无法短路。

如果您知道A = true,则(A XOR B)=!B。

如果您知道A = false,则(A XOR B)=B。

在这两种情况下,如果您了解A但不了解B,则您所了解的不足(A XOR B)。您必须始终学习A和B的值才能计算出答案。实际上,没有用例可以解决没有两个值的XOR。

请记住,按定义XOR有四种情况:

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

再次,希望从上面显而易见的是,在不知道第二个值的情况下,知道第一个值永远不足以得到答案。但是,在您的问题中,您省略了第一种情况。如果您反而想要

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

那么您确实可以通过短路条件操作来实现:

A && !B

但这不是异或。


我没有在此答案中看到任何至少在以上答案中没有的东西。我没有看到任何迹象表明您的OP一直在寻找您的可短路异或,因为他接受了一个假设,即他想进行适当的异或。
15ee8f99-57ff-4f92-890c-b56153 '19

从字面上看,我的建议是到目前为止唯一可以在不评估第二个参数的情况下生成OP要求的真值表的答案。
凯文·霍尔特

OP还询问了为什么没有条件XOR,并且上面的答案确实正确地说明了这是因为XOR需要两个参数,IMO上面的答案似乎并未充分说明为什么XOR实际上需要两个参数。显然,您感到不一样,但是对我而言,从本页上的各种评论中可以明显看出,XOR的基本两个论点尚未完全向一个完整的初学者解释。
凯文·霍尔特

1
你说服了我。
15ee8f99-57ff-4f92-890c-b56153

@Kevin Holt-如果您需要满足以下条件之一,但不是同时满足两个条件,则逻辑XOR是有意义的。您必须评估两个条件都没有关系。短路是底层细节,您在处理对性能有严格要求的代码时只需担心(控制流很慢)。当使逻辑运算符成为逻辑运算符时,我会更关心“异或”的含义。也就是说,让它像按位版本那样运行(像其他运算符一样),或者使其成为或独占的(尽可能多的条件,但只有一个为真)。
瑟勒姆,

-3

这个问题已经得到了解答,但我遇到了另一种情况。的确,不需要条件XOR。也可以使用^运算符。但是,如果只需要测试操作数的“真||假”状态,则^会导致麻烦。例如:

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

在此示例中,如果将left设置为10(0xa),将right设置为5(0x5),则输入“成功”分支。对于此示例(如果愚蠢的话是简单的),这将导致错误,因为您不应同时向左和向右转。我从发问者那里得到的并不是他实际上想要一个条件,而是一种简单的方法,对传递给异或值的值执行真/假。

宏可以解决问题:

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

如果我不喜欢,请随意打我:o)

发布此消息后,我在下面阅读了吉姆雷德(Jimreed)的回答(糟糕的Yapdog!),而他的回答实际上更简单。它将奏效,我完全不知道为什么他的答案被否决了。


3
这是一个C#问题,而不是C / C ++。 if需要一个布尔表达式,它甚至不会使用int进行编译。
Marc L.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.