xor有3个值

sia*_*ana 26 c# conditional operators

我需要在3个值之间做一个xor条件,即我需要三个值中的一个为真但不超过一个而不是没有.

我以为我可以使用xor ^运算符,但它没有按预期工作.

我预计这会返回假,但它不会.(true ^ true ^ true)

所有其他组合似乎按我的预期工作.

在查看xor运算符的文档时,他们只讨论比较2个值,并且我无法在线查找3个或更多值的任何内容.

任何人都可以放弃任何亮点或建议一个简单的方法吗?

jco*_*ctx 16

一种方法是将布尔值转换为整数,添加结果,并与1进行比较.


Chr*_*ris 11

((true ^ true) ^ true)将返回true,这不是你所期望的true ^ true ^ true.

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

if ((a && !b && !c) || (!a && b && !c) || (!a && !b && c))
Run Code Online (Sandbox Code Playgroud)

或者,根据@jcomeau_ictx答案,您可以执行以下操作:

if( Convert.ToInt32(a) + Convert.ToInt32(b) + Convert.ToInt32(c) == 1 )
Run Code Online (Sandbox Code Playgroud)

或者,您可以创建一个函数:

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));
}
Run Code Online (Sandbox Code Playgroud)

编辑:您可能想要命名该函数,TernaryXor以便更清楚该函数的结果.


Ray*_*Ray 11

因为我无法得到足够的Linq,怎么样:

new[] { a, b, c }.Count(v => v) == 1


Kub*_*uba 6

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


Jim*_*hel 5

这肯定是一个棘手的问题。鉴于你想要的:

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
Run Code Online (Sandbox Code Playgroud)

这将做到:

rslt = (!a & (b ^ c)) || (a & !(b | c));
Run Code Online (Sandbox Code Playgroud)

第一部分处理 wherea为 0的四种情况。 第二部分, wherea不为 0。

一种更简单的方式来看待它是这样的:

rslt = (a | b | c) & !((a & b) | (a & c) | (b & c))
Run Code Online (Sandbox Code Playgroud)

也就是说,三个中的一个必须是真的,但没有两个(或更多)是真的。

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

编辑

我认为这是我今天早上正在寻找的解决方案:

rslt = a ? !(b | c) : (b ^ c);
Run Code Online (Sandbox Code Playgroud)

现在,至于为什么我使用|而不是||

这是风格问题和对分支的旧偏见的结合(旧习惯很难改掉)。 !(b | c)生成此 IL 代码:

ldarg.1
ldarg.2
or
ldc.i4.0
ceq
stloc.0
Run Code Online (Sandbox Code Playgroud)

该代码中没有任何分支。如果我使用||,如在 中!(b ||c),它会生成:

  ldarg.1
  brfalse.s IL_009B
  ldarg.2
  br.s IL_009C
IL_009B:
  ldc.i4.1
IL_009C:
  stloc.0
Run Code Online (Sandbox Code Playgroud)

其中有两个分支。我不知道 JIT 生成的代码是否会反映这一点,但我怀疑它会。所以一位代码是 6 条总是被执行的指令。另一个是6条指令,有时只执行4条。但是分支惩罚很可能会消耗不执行两条指令的任何收益。

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

但我告诉你,它肯定曾经使用过!在分支非常昂贵的 8086 上,(b | c)和之间的差异(b || c)巨大的

最后,|正如您所指出的,使用 强制对整个表达式进行评估。我的原始代码实际上说,“如果这个表达式为真那个表达式为真。” 使用&&并将||其变成一堆条件,在我的脑海中,更难阅读。

所以:基于最可能过时的性能考虑的旧偏见。但无害。

但是,必须小心,(b() | c())除非必须评估两个函数,否则不要编写类似的东西。