【问题标题】:XOR of three values三个值的异或
【发布时间】:2011-03-28 20:15:13
【问题描述】:

进行三路异或的最简单方法是什么?

换句话说,我有三个值,我想要一个评估为真 IFF 的语句只有 三个值中的一个为真。

到目前为止,这是我想出的:

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

有没有更简单的方法来做同样的事情?


这是上面完成任务的证明:

a = true; b = true; c = true
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> false

a = true; b = true; c = false
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> false

a = true; b = false; c = true
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> false

a = true; b = false; c = false
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> true

a = false; b = true; c = true
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> false

a = false; b = true; c = false
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> true

a = false; b = false; c = true
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> true

a = false; b = false; c = false
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> false

【问题讨论】:

    标签: language-agnostic logic boolean xor boolean-expression


    【解决方案1】:

    对于三个术语,您可以使用以下表达式:

    (a ^ b ^ c) && !(a && b && c)
    

    如果其中一个或三个术语是true,则第一部分是true。表达式的第二部分确保不是所有三个都是true

    请注意,上面的表达式确实推广到更多的术语。一个更通用的解决方案是实际计算有多少个术语是true,所以是这样的:

    int trueCount =
       (a ? 1 : 0) +
       (b ? 1 : 0) +
       (c ? 1 : 0) +
       ... // more terms as necessary 
    
    return (trueCount == 1); // or some range check expression etc
    

    【讨论】:

    • 很好,但一般的解决方案不会短路。
    • a ? 1 : 0 可以简化为!!a
    • @gg.kaspersky,仅在 JavaScript、C 和通过 ! 运算符进行真/假测试的语言中。例如,这不适用于 Java 或 C#。
    • @DrewNoakes,当我发表评论时,出于某种原因,我认为这个问题是特定于 C 的。实际上,某些语法结构仅在某些语言中有效。
    【解决方案2】:
    bool result = (a?1:0)+(b?1:0)+(c?1:0) == 1;
    

    【讨论】:

    • 我喜欢它。非常简单易懂。
    • 最简单的,阅读代码时必须可以理解(好吧,我会添加几个空格)
    【解决方案3】:

    a^b^c 只有在奇数个变量为 1 时才为 1(两个“1”会相互抵消)。所以你只需要检查“所有三个都是1”的情况:

    result = (a^b^c) && !(a&&b&&c)
    

    【讨论】:

      【解决方案4】:

      另一种可能性:

      a ? !b && !c : b ^ c
      

      恰好比接受的答案短 9 个字符 :)

      【讨论】:

      • 有点高兴这不是因为可读性原因而被接受的答案,但我仍然不得不投票,因为简短仍然对我有一些古怪的吸引力。在大学的 C 课上,我们有一个编写最短源代码的竞赛,该竞赛生成一首类似于 Heidis Kuken 的歌曲,我在竞赛中获得了 TOP 5。
      【解决方案5】:

      您也可以尝试(在 C 中):

      !!a + !!b + !!c == 1

      【讨论】:

      • 这仅在某些语言中有效[例如。 javascript],这不是简化。在将布尔值自动转换为 + 的数字的语言中,如果 abc 已经是布尔值,您也不需要双重否定 !!:只需 a+b+c===1 即可等价。
      • @blgt,我的错误,我应该说明我的意思是成为 C 语言的答案。
      • 使用!! 来保证C 为true 是1 实际上非常简洁。不过,在布尔逻辑问题的上下文中有点偏执。如果你的其余代码写得很好a+b+c==1应该仍然足够
      【解决方案6】:

      在 Python 上更好:

      result = (1 if a else 0)+(1 if b else 0)+(1 if c else 0) == 1
      

      这也可以用于 if 语句!

      它通过 Click 为 CLI 互斥参数节省了我的时间(每个人都讨厌点击)

      【讨论】:

        【解决方案7】:

        这是一个通用实现,当发现多个booltrue 时会迅速失败。

        用法

        XOR(a, b, c);
        

        代码

        public static bool XOR(params bool[] bools)
        {
            return bools.Where(b => b).AssertCount(1);
        }
        
        public static bool AssertCount<T>(this IEnumerable<T> source, int countToAssert)
        {
            int count = 0;
            foreach (var t in source)
            {
                if (++count > countToAssert) return false;
            }
        
            return count == countToAssert;
        }
        

        【讨论】:

          【解决方案8】:
          f= lambda{ |a| [false, false, true].permutation.to_a.uniq.include? a }
          p f.call([false, true, false])
          p f.call([false, true, true])
          

          $ 真

          $ 假

          因为我可以。

          【讨论】:

            猜你喜欢
            • 2019-02-06
            • 2014-07-16
            • 1970-01-01
            • 1970-01-01
            • 2013-08-20
            • 1970-01-01
            • 1970-01-01
            • 2016-07-18
            • 2020-02-24
            相关资源
            最近更新 更多