xor with 3 values

后端 未结 10 1437
野性不改
野性不改 2020-12-30 22:12

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 ^ op

相关标签:
10条回答
  • 2020-12-30 22:14

    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.

    0 讨论(0)
  • 2020-12-30 22:16

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

    0 讨论(0)
  • 2020-12-30 22:19

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

    0 讨论(0)
  • 2020-12-30 22:20

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

    0 讨论(0)
  • 2020-12-30 22:26

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

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

    0 讨论(0)
  • 2020-12-30 22:34

    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)

    0 讨论(0)
提交回复
热议问题