C# 三值异或

C# 三值异或,c#,operators,conditional,C#,Operators,Conditional,我需要在3个值之间做一个异或条件,即我需要三个值中的一个为真,但不超过一个且不为零 我想我可以使用xor^运算符来实现这一点,但它没有按预期工作 我原以为这会返回false,但事实并非如此。 (对^对^对) 所有其他组合似乎都像我预期的那样起作用 当查看xor运算符的文档时,他们只讨论比较2个值,我在网上找不到任何关于对3个或更多值进行比较的内容 有人能解释一下或建议一种简单的方法吗?XOR是一种二进制运算符,一次只能对2个值使用。所以当你做(真异或真异或真),它实际上做((真异或真)异或真)

我需要在3个值之间做一个异或条件,即我需要三个值中的一个为真,但不超过一个且不为零

我想我可以使用xor^运算符来实现这一点,但它没有按预期工作

我原以为这会返回false,但事实并非如此。 (对^对^对)

所有其他组合似乎都像我预期的那样起作用

当查看xor运算符的文档时,他们只讨论比较2个值,我在网上找不到任何关于对3个或更多值进行比较的内容


有人能解释一下或建议一种简单的方法吗?

XOR是一种二进制运算符,一次只能对2个值使用。所以当你做
(真异或真异或真)
,它实际上做
((真异或真)异或真)

内部
(true或XOR true)
解析为
false
,因为它们是相同的。解决该问题后,余数为
(false或true)
,解析为
true

听起来你在试图聪明或高效地匹配你的条件。这可能会花费我几分钟的时间来弄清楚,然后写一个真值表或测试,以确保它正确处理所有可能的组合

如果(countTrues==1),只需计算其中有多少是
true
,并执行
if(countTrues==1)
,就简单多了。这是因为它没有显著的开销,而且与只使用位旋转的解决方案相比,它实际上是可读和可理解的(这里有几个其他的答案可以证明它)。

使用异或,
if(false^false^false)
应该返回
false
。XOR的工作方式是支持XOR的。如果一个且只有一个元素为true,则Exclusive Or返回true。如果它们都是假的,它将返回false

如果要使用3个值,例如a、b和c,则表达式应类似于: (a或b或c)及(a及b)及(a及c)及(b及c)

这里有一个更合适的格式:
(a v b v c)*~(a*b)*~(a*c)*~(b*c)

一种方法是转换,添加结果,并与1进行比较。

((true^true)^true)
将返回
true
,这不是您从
true^true^true
中所期望的结果

要确保获得想要的结果(只有一个值为真),请执行以下操作:

if ((a && !b && !c) || (!a && b && !c) || (!a && !b && c))
if( Convert.ToInt32(a) + Convert.ToInt32(b) + Convert.ToInt32(c) == 1 )
或者,根据@jcomeau_ictx answer,您可以执行以下操作:

if ((a && !b && !c) || (!a && b && !c) || (!a && !b && c))
if( Convert.ToInt32(a) + Convert.ToInt32(b) + Convert.ToInt32(c) == 1 )
或者,您可以创建一个函数:

public bool TernaryXor(bool a, bool b, bool c)
{
    //return ((a && !b && !c) || (!a && b && !c) || (!a && !b && c));

    // taking into account Jim Mischel's comment, a faster solution would be:
    return (!a && (b ^ c)) || (a && !(b || c));
}

编辑:您可能希望将函数命名为
TernaryXor
,以便更清楚地了解函数的结果。

XOR是一个二进制运算符,不能在两个以上的操作数上运行。根据操作顺序,当您查看:
(false^false^false)
时,您确实得到了“((false^false)^false)”

在mindm中,在评估这是否适用于您方面,为您所需的操作构建一个真值表可能很有用。对于上面列出的示例,您将看到:

(Op1 XOR Op2) XOR Op3 = Result    
 F       F        F     F
 F       F        T     T 
 F       T        F     T 
 F       T        T     F
 T       F        F     T
 T       F        T     F
 T       T        F     F
 T       T        T     T

这使得在所有操作数都为真的情况下,XOR成为一个问题,可能需要一些特殊的处理,比如添加and not(Op1、Op2和Op3)。

因为我无法获得足够的Linq,那么:


new[]{a,b,c}。计数(v=>v)==1

这很短!(a&&b&&c)&&(a^b^c)

这肯定是个棘手的问题。考虑到您的需求:

a b c rslt
0 0 0  0
0 0 1  1
0 1 0  1
0 1 1  0
1 0 0  1
1 0 1  0
1 1 0  0
1 1 1  0
这可以做到:

rslt = (!a & (b ^ c)) || (a & !(b | c));
第一部分处理
a
为0的四种情况。第二部分,其中
a
不是0

更简单的方法是:

rslt = (a | b | c) & !((a & b) | (a & c) | (b & c))
也就是说,三者中必须有一个是真的,但没有两个(或更多)是真的

似乎应该有一种进一步简化的方法,但我没有想到。也许我需要更多的咖啡因

编辑

我想这就是我今天早上想要的解决方案:

rslt = a ? !(b | c) : (b ^ c);
现在,至于我为什么用
|
而不是
|

这是一个风格问题和对分支的旧偏见的结合(旧习惯难以改变)<代码>!(b | c)生成此IL代码:

ldarg.1
ldarg.2
or
ldc.i4.0
ceq
stloc.0
该代码中没有任何分支。如果我使用
|
,就像在
中一样!(b | | c)
,它生成:

  ldarg.1
  brfalse.s IL_009B
  ldarg.2
  br.s IL_009C
IL_009B:
  ldc.i4.1
IL_009C:
  stloc.0
它有两个分支。我不知道JIT生成的代码是否会反映这一点,但我怀疑它会。因此,一位代码是始终执行的6条指令。另一种是6条指令,有时只执行4条指令。但分支惩罚很可能会耗尽不执行其中两条指令所获得的任何收益

我意识到现代CPU在分支方面比8086要好得多,而且这两个代码段的运行时可能没有任何可检测的差异。即使有,它也不可能对我通常编写的程序的总体运行时间产生重大影响

但我告诉你,过去确实如此!在分支非常昂贵的8086上,
(b | c)
(b | c)
之间的差异是巨大的

最后,如您所述,使用
|
,强制计算整个表达式。我的原始代码实际上是这样写的,“如果这个表达式是真的,或者那个表达式是真的。”使用
&
|
将它转换成一堆条件句,在我的大脑中,它更难阅读

因此:基于最可能过时的性能考虑的旧偏见。但是无害


但是,我们必须小心,不要编写类似于
(b()| c())
的东西,除非必须对这两个函数进行求值。

在我试图解决自己的问题时遇到了这个问题(4个值的异或);确定LINQ是处理N情况下此问题的最简单方法

bool OneAndOnlyOneIsTrue(IEnumerable<bool> conditions)
{
    return conditions.Count(c => c) == 1;
}
指令方面,这将检查每个条件一次,所以函数是O(n),但它是灵活和该死的站点mo