与 3 个值进行异或

发布于 2024-11-13 04:16:08 字数 274 浏览 1 评论 0原文

我需要在 3 个值之间进行异或条件,即我需要三个值之一为 true,但不能超过 1 个,也不能没有。

我以为我可以使用 xor ^ 运算符来实现此目的,但它没有按预期工作。

我预计这会返回 false,但事实并非如此。 (true ^ true ^ true)

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

当查看异或运算符的文档时,他们只讨论比较 2 个值,而我在网上找不到任何关于对 3 个或更多值执行此操作的信息。

谁能阐明或建议一种简单的方法来做到这一点?

I need to do an xor conditional between 3 values, ie i need one of the three values to be true but not more than one and not none.

I thought i could use the xor ^ operator for this but its not working as expected.

I expected that this would return false but it doesnt.
(true ^ true ^ true)

all other combinations seem to work as i expected.

When looking at the docs for the xor operator they only talk about comparing 2 values and i cant find anything on doing this for 3 or more values online.

Can anyone shed any light or suggest a simple way of doing this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

聊慰 2024-11-20 04:16:08

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

One way would be to convert the Boolean values to an integer, add the results, and compare to 1.

喜你已久 2024-11-20 04:16:08

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

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

if ((a && !b && !c) || (!a && b && !c) || (!a && !b && c))

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

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,以便更清楚地了解函数的结果。

((true ^ true) ^ true) will return true, which is not what you would expect from true ^ true ^ true.

To make sure that you get the outcome you want (only one value to be true) do the following:

if ((a && !b && !c) || (!a && b && !c) || (!a && !b && c))

Alternatively, based on @jcomeau_ictx answer, you can do the following:

if( Convert.ToInt32(a) + Convert.ToInt32(b) + Convert.ToInt32(c) == 1 )

Or, you could create a function:

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));
}

EDIT: You might want to name the function TernaryXor so that it is more clear as to the outcome of the function.

挥剑断情 2024-11-20 04:16:08

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

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

Because I can't get enough Linq, how about:

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

唱一曲作罢 2024-11-20 04:16:08

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

this is short !(a&&b&&c) && (a^b^c)

木槿暧夏七纪年 2024-11-20 04:16:08

当然,这是一个棘手的问题。给定你想要的:

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()) 的内容,除非必须对两个函数进行求值。

It's a tricky one, for sure. Given what you want:

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

This will do it:

rslt = (!a & (b ^ c)) || (a & !(b | c));

The first part handles the four cases where a is 0. The second part, where a is not 0.

A simpler way to look at it is this:

rslt = (a | b | c) & !((a & b) | (a & c) | (b & c))

That is, one of the three must be true, but no two (or more) can be true.

It seems like there should be a way to simplify further, but it's not coming to mind. Maybe I need more caffeine.

EDIT

I think this one is the solution I was looking for this morning:

rslt = a ? !(b | c) : (b ^ c);

Now, as to why I used | instead of ||:

It's a combination of a style issue and an old bias against branching (old habits die hard). !(b | c) generates this IL code:

ldarg.1
ldarg.2
or
ldc.i4.0
ceq
stloc.0

There aren't any branches in that code. If I use ||, as in !(b ||c), it generates:

  ldarg.1
  brfalse.s IL_009B
  ldarg.2
  br.s IL_009C
IL_009B:
  ldc.i4.1
IL_009C:
  stloc.0

Which has two branches. I don't know if the JIT-produced code will mirror that, but I suspect it will. So one bit of code is 6 instructions that are always executed. The other is 6 instructions of which sometimes only 4 are executed. But branching penalties might very well eat up any gains from not executing two of the instructions.

I realize that modern CPUs are much better at branching than the 8086 was, and there might not be any detectable difference in the runtime of these two code snippets. Even if there were, it's unlikely that it would make a significant difference in the overall runtime of the programs I typically write.

But I tell you that it certainly used to! On the 8086, where branching was very expensive, the difference between (b | c) and (b || c) was huge.

Finally, using |, as you noted, forces evaluation of the entire expression. My original code says, in effect, "if this expression is true or that expression is true." Using && and || turns it into a bunch of conditionals and is, in my brain, more difficult to read.

So: an old prejudice based on most likely outdated performance considerations. But harmless.

One has to be careful, though, not to write something like (b() | c()) unless both functions must be evaluated.

哭了丶谁疼 2024-11-20 04:16:08

使用 XOR,if (false^false^false) 应返回 false。它正在按照 XOR 的预期工作方式进行。 Exclusive Or 如果一个且只有一个元素为 true,则返回 true。如果全部为 false,则返回 false。

如果您想使用 3 个值(例如 a、b 和 c)来执行此操作,则表达式应类似于:
(a 或 b 或 c) 和 ~(a 和 b) 和 ~(a 和 c) 和 ~(b 和 c)

这是更合适的格式:
(avbvc) * ~(a * b) * ~(a * c) * ~(b * c)

Using XOR, if (false^false^false) should return false. It is working how XOR is supposted to work. Exclusive Or returns true if one and only one of the elements is true. If they are all false, it will return false.

If you want to do it with 3 values, say a,b and c, the expression should be something like:
(a or b or c) and ~(a and b) and ~(a and c) and ~(b and c)

heres a more proper format:
(a v b v c) * ~(a * b) * ~(a * c) * ~(b * c)

时间你老了 2024-11-20 04:16:08

XOR 是二元运算符,不适用于两个以上的操作数。给定操作顺序,当您查看:(false ^ false ^ false)时,您实际上得到了`((false ^ false) ^ false)。

记住这一点,在评估这是否适合您时,为您所需的操作建立一个真值表可能会很有用。在上面列出的示例中,您正在查看:

(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

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

XOR is a binary operator and does not function on more than two operands. Given the order of operations, when you are looking at: (false ^ false ^ false) you are really getting `((false ^ false) ^ false).

Bearing that in mindm, in terms of evaluating whether this is going to work for you, it may be useful to build yourself a truth table for your desired operation. In the case of the example listed above you are looking at:

(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

Which makes XOR a problem in the case where all operands are true and may require some special handling say by adding an AND not (Op1 AND Op2 AND Op3).

乖乖兔^ω^ 2024-11-20 04:16:08

XOR 是一个二元运算符,它一次只能用于 2 个值。因此,当您执行 (true XOR true XOR true) 时,它实际上会执行 ((true XOR true) XOR true)...

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

听起来你正试图以聪明或超级高效的方式来满足你的条件。这可能需要我花几分钟的时间来弄清楚,然后编写一个真值表或测试以确保它正确处理所有可能的组合。

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

XOR is a binary operator, it can only be used on 2 values at a time. So when you do (true XOR true XOR true), it actually does ((true XOR true) XOR true)...

The inner (true XOR true) resolves to false because they're the same. With that resolved, the remainder is (false XOR true), which resolves to true.

It sounds like you're trying to be clever or super-efficient about matching your conditions. This would probably take me several minutes to puzzle out and then write a truth-table or test to make sure it treats all possible combinations correctly.

It is so much simpler to just count how many of them are true and do if (countTrues == 1). The reason for this is that it doesn't have significant overhead, and it is actually readable and understandable compared to a solution using only bit-twiddling (there are a couple other answers here that demonstrate it).

晨光如昨 2024-11-20 04:16:08

当我走上错误的道路试图解决我自己的问题时遇到了这个问题(跨 4 个值进行异或);确定 LINQ 是处理 N 情况问题的最简单方法;

bool OneAndOnlyOneIsTrue(IEnumerable<bool> conditions)
{
    return conditions.Count(c => c) == 1;
}

调用方式如下;

bool OneLuckyGuy(Person p1, Person p2, Person p3, Person p4)
{
     return OneAndOnlyOneIsTrue(new [] {         
         p1.IsAMan(),
         p2.IsAMan(),
         p3.IsAMan(),
         p4.IsAMan()
     });
}

从指令角度来看,这将检查每个条件一次,因此函数的复杂度为 O(n),但它很灵活,并且比按位替代方案更具可读性。 ;-)

Came across this while I went down the wrong path trying to solve my own problem (XOR across 4 values); decided that LINQ is the simplest way to handle this problem for an N-case;

bool OneAndOnlyOneIsTrue(IEnumerable<bool> conditions)
{
    return conditions.Count(c => c) == 1;
}

Invoked like;

bool OneLuckyGuy(Person p1, Person p2, Person p3, Person p4)
{
     return OneAndOnlyOneIsTrue(new [] {         
         p1.IsAMan(),
         p2.IsAMan(),
         p3.IsAMan(),
         p4.IsAMan()
     });
}

Instruction-wise, this will check each condition once, so function is O(n), but it's flexible and a damn site more readable than the bitwise alternative. ;-)

沙沙粒小 2024-11-20 04:16:08

解决方案很简单

a = true; b = false; c = true

(a ^ b) || (a ^ c)

the solution simple it's

a = true; b = false; c = true

(a ^ b) || (a ^ c)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文