74

I'm trying to understand the binary operators in C# or in general, in particular ^ - exclusive or.

For example:

Given an array of positive integers. All numbers occur even number of times except one number which occurs odd number of times. Find the number in O(n) time and constant space.

This can be done with ^ as follows: Do bitwise XOR of all the elements. Finally we get the number which has odd occurrences.

How does it work?

When I do:

int res = 2 ^ 3;  
res = 1;  
int res = 2 ^ 5;  
res = 7;  
int res = 2 ^ 10;  
res = 8;  

What's actually happening? What are the other bit magics? Any reference I can look up and learn more about them?

Community
  • 1
  • 1
DarthVader
  • 52,984
  • 76
  • 209
  • 300
  • 11
    It is binary addition without carries. 0+0 = 0, 1+0=1, 0+1=1, and 1+1=0 (no carry). Normal binary addition for 1+1 would be 0 carry 1. – dbasnett Jun 20 '11 at 10:52

8 Answers8

155

I know this is a rather old post but I wanted simplify the answer since I stumbled upon it while looking for something else.
XOR (eXclusive OR/either or), can be translated simply as toggle on/off.
Which will either exclude (if exists) or include (if nonexistent) the specified bits.

Using 4 bits (1111) we get 16 possible results from 0-15:

 decimal | binary | bits (expanded)
       0 | 0000   | 0
       1 | 0001   | 1
       2 | 0010   | 2
       3 | 0011   | (1+2)
       4 | 0100   | 4
       5 | 0101   | (1+4)
       6 | 0110   | (2+4) 
       7 | 0111   | (1+2+4)
       8 | 1000   | 8
       9 | 1001   | (1+8)
      10 | 1010   | (2+8)
      11 | 1011   | (1+2+8)
      12 | 1100   | (4+8)
      13 | 1101   | (1+4+8)
      14 | 1110   | (2+4+8)
      15 | 1111   | (1+2+4+8)

The decimal value to the left of the binary value, is the numeric value used in XOR and other bitwise operations, that represents the total value of associated bits. See Computer Number Format and Binary Number - Decimal for more details.

For example: 0011 are bits 1 and 2 as on, leaving bits 4 and 8 as off. Which is represented as the decimal value of 3 to signify the bits that are on, and displayed in an expanded form as 1+2.


As for what's going on with the logic behind XOR here are some examples
From the original post

2^3 = 1

  • 2 is a member of 1+2 (3) remove 2 = 1

2^5 = 7

  • 2 is not a member of 1+4 (5) add 2 = 1+2+4 (7)

2^10 = 8

  • 2 is a member of 2+8 (10) remove 2 = 8

Further examples

1^3 = 2

  • 1 is a member of 1+2 (3) remove 1 = 2

4^5 = 1

  • 4 is a member of 1+4 (5) remove 4 = 1

4^4 = 0

  • 4 is a member of itself remove 4 = 0

1^2^3 = 0
Logic: ((1^2)^(1+2))

  • (1^2) 1 is not a member of 2 add 2 = 1+2 (3)
  • (3^3) 1 and 2 are members of 1+2 (3) remove 1+2 (3) = 0

1^1^0^1 = 1
Logic: (((1^1)^0)^1)

  • (1^1) 1 is a member of 1 remove 1 = 0
  • (0^0) 0 is a member of 0 remove 0 = 0
  • (0^1) 0 is not a member of 1 add 1 = 1

1^8^4 = 13
Logic: ((1^8)^4)

  • (1^8) 1 is not a member of 8 add 1 = 1+8 (9)
  • (9^4) 1 and 8 are not members of 4 add 1+8 = 1+4+8 (13)

4^13^10 = 3
Logic: ((4^(1+4+8))^(2+8))

  • (4^13) 4 is a member of 1+4+8 (13) remove 4 = 1+8 (9)
  • (9^10) 8 is a member of 2+8 (10) remove 8 = 2
  • 1 is not a member of 2+8 (10) add 1 = 1+2 (3)

4^10^13 = 3
Logic: ((4^(2+8))^(1+4+8))

  • (4^10) 4 is not a member of 2+8 (10) add 4 = 2+4+8 (14)
  • (14^13) 4 and 8 are members of 1+4+8 (13) remove 4+8 = 1
  • 2 is not a member of 1+4+8 (13) add 2 = 1+2 (3)
Will B.
  • 17,883
  • 4
  • 67
  • 69
  • 8
    You are still getting +1. Thanks for the effort for newer users and for those who are curious. – DarthVader Apr 29 '13 at 17:59
  • Awesome. From where did you get to know this? Can you give some reference for learning other bitwise operations? – ashwani Jan 04 '16 at 13:57
  • 1
    @user132458 honestly it is just what I came to understand about how bitwise operations work. Best resources would depend on your use case, such as program language. EG: C# vs PHP vs Python and how they utilize bitwise operations and their limitations. However wiki is a decent resource in regards to general bitwise operations https://en.wikipedia.org/wiki/Bitwise_operation. – Will B. Jan 04 '16 at 14:14
  • In 2^5, you said *"2 is not a member of 1+4 (5) add 2 = 1+2+4 (7)"*. But why do you assume 5 is 1+4 instead of 2 + 3? In that case, 2 would be member of 2+3. I didn't get this part. – Alisson Reinaldo Silva Apr 17 '18 at 16:36
  • @Alisson If you look at the chart at the top of my answer, it displays the binary number representation conversion. The number value is the total value of the position of the bits that are enabled. e.g. `5` is the value of `0101` which are bits `1 and 4` or rather `1+4 = 5`. The numerical 3 in bitwise operations is represented as bits `1 and 2` or `0011` Which would make `2 + 3` actually be `2 + (1+2)`. For more details please see: [Binary number representation](https://en.wikipedia.org/wiki/Computer_number_format) – Will B. Apr 17 '18 at 17:44
  • 2
    No explanation could have been better than this. – Raghav salotra Jun 10 '18 at 10:30
  • 1
    @WillB. The explanation of when it acts as `add` and when as `remove` is awesome!!! – Gaurav Singh Aug 11 '21 at 06:07
67

To see how it works, first you need to write both operands in binary, because bitwise operations work on individual bits.

Then you can apply the truth table for your particular operator. It acts on each pair of bits having the same position in the two operands (the same place value). So the leftmost bit (MSB) of A is combined with the MSB of B to produce the MSB of the result.

Example: 2^10:

    0010 2
XOR 1010 8 + 2
    ----
    1    xor(0, 1)
     0   xor(0, 0)
      0  xor(1, 1)
       0 xor(0, 0)
    ----
 =  1000 8

And the result is 8.

Jason
  • 6,878
  • 5
  • 41
  • 55
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
35

The other way to show this is to use the algebra of XOR; you do not need to know anything about individual bits.

For any numbers x, y, z:

XOR is commutative: x ^ y == y ^ x

XOR is associative: x ^ (y ^ z) == (x ^ y) ^ z

The identity is 0: x ^ 0 == x

Every element is its own inverse: x ^ x == 0

Given this, it is easy to prove the result stated. Consider a sequence:

a ^ b ^ c ^ d ...

Since XOR is commutative and associative, the order does not matter. So sort the elements.

Now any adjacent identical elements x ^ x can be replaced with 0 (self-inverse property). And any 0 can be removed (because it is the identity).

Repeat as long as possible. Any number that appears an even number of times has an integral number of pairs, so they all become 0 and disappear.

Eventually you are left with just one element, which is the one appearing an odd number of times. Every time it appears twice, those two disappear. Eventually you are left with one occurrence.

[update]

Note that this proof only requires certain assumptions about the operation. Specifically, suppose a set S with an operator . has the following properties:

Assocativity: x . (y . z) = (x . y) . z for any x, y, and z in S.

Identity: There exists a single element e such that e . x = x . e = x for all x in S.

Closure: For any x and y in S, x . y is also in S.

Self-inverse: For any x in S, x . x = e

As it turns out, we need not assume commutativity; we can prove it:

(x . y) . (x . y) = e  (by self-inverse)
x . (y . x) . y = e (by associativity)
x . x . (y . x) . y . y = x . e . y  (multiply both sides by x on the left and y on the right)
y . x = x . y  (because x . x = y . y = e and the e's go away)

Now, I said that "you do not need to know anything about individual bits". I was thinking that any group satisfying these properties would be enough, and that such a group need not necessarily be isomorphic to the integers under XOR.

But @Steve Jessup proved me wrong in the comments. If you define scalar multiplication by {0,1} as:

0 * x = 0
1 * x = x

...then this structure satisfies all of the axioms of a vector space over the integers mod 2.

Thus any such structure is isomorphic to a set of vectors of bits under component-wise XOR.

Nemo
  • 70,042
  • 10
  • 116
  • 153
  • And it has that algebra because it's just addition in a vector space over the prime field of order 2. And that's because in that field, the sum of two values is 1 if and only if exactly one of the summands is 1. A logical XOR of two boolean values is true if and only if exactly one of the operands is true. So logical XOR is addition in the field, and then "bitwise" makes it a vector space. – Steve Jessop Jun 19 '11 at 00:28
  • @Steve: A fair point. Which leads to an interesting question... Any group obeying these relationships will have the property identified in the question. But are all such groups isomorphic to (Z/2Z)^n for some n? – Nemo Jun 19 '11 at 00:37
  • @Nemo: that might depend what you mean by `n`. For example, consider vector spaces with infinite bases over that field. – Steve Jessop Jun 19 '11 at 00:51
  • @Steve: OK, call it a finite group then. In other words, if a finite group is associative, commutative, and self-inverse, it is necessarily isomorphic to some n-dimensional vector space over {0,1} ? – Nemo Jun 19 '11 at 00:55
  • I think so, yes - if we take any group with those properties and define the obvious scalar multiplication, then we have a vector space over that field. Whether it necessarily has a dimension is equivalent to the Axiom of Choice (the proof being easier in one direction than the other), but if it's finite then it certainly does :-) – Steve Jessop Jun 19 '11 at 00:56
  • @Steve: Sorry, but I am not following you. What is the "obvious scalar multiplication" in this context? All we have are the group properties plus the ones mentioned; there is no immediate mapping to reals, integers, or 0/1. Put another way, given group elements a and b satisfying these properties, what is their scalar product? – Nemo Jun 19 '11 at 01:01
  • Using the notation that `0` is the scalar 0, and `e` is the group identity, then the "obvious scalar multiplication" is that `0 * a == e` and `1 * a == a` for all elements `a` in the group. In fact that's the only scalar multiplication you can define that makes it a vector space - those identities hold for all vector spaces regardless of the field. I'm not talking about the scalar product of two vectors, that's not part of the definition of a vector space and need not be defined. A vector space with a defined scalar product of two vectors is called an "inner product space". – Steve Jessop Jun 19 '11 at 01:07
  • My point being that once you've defined that multiplication-by-0-or-1, the group immediately *is* a vector space over (Z/2Z), which proves the isomorphism. – Steve Jessop Jun 19 '11 at 01:09
  • @Steve: Except my proof does not need 0 to be the scalar zero. Let me rephrase my question. Suppose we have a finite group that is associative, commutative, and self-inverse. Suppose it has an identity (not necessarily anything to do with the integer 0). That is all you know about the group; its elements could be anything, they just obey those relations. Is that group necessarily isomorphic to some n-dimensional vector space over {0,1}? (Note my proof shows that any such group has the property described in the question; it did not actually rely on the number `0` being the identity.) – Nemo Jun 19 '11 at 01:13
  • @Nemo: yes, it is. A vector space by definition consists of a commutative group, a field, and a "scalar multiplication operation" which is a binary operator taking a member of the field (a "scalar") together with a member of the group (a "vector") and returning a member of the group. The "scalar zero" is by definition the multiplicative identity of the field. Since the field that I'm using to construct my vector space is Z(2), that means the scalar zero is the integer 0. It has nothing to do with the fact that in bitwise XOR, the *group* identity also happens to be the integer 0. – Steve Jessop Jun 19 '11 at 01:18
  • @Steve: We are still talking past each other. Let me try again. _What if there is no scalar multiplication at all_? What if all you know is that the _group multiplication_ (which takes two elements of the group and yields another element of the group) obeys the given properties? Given _only_ those properties -- including that some element, not necessarily called "0", is an identity -- can you then prove isomorphism to the integers under XOR? – Nemo Jun 19 '11 at 01:21
  • I'm *defining* a scalar multiplication. I'm just inventing this binary operator by stating that `0*a==e` and `1*a==a`. It is my right as a mathematician to define functions, and the reason this one is interesting is because together with the field Z(2) and the self-inverse group which you provide, it satisfies the vector space axioms (I claim this without having shown the working to prove it). And btw it will get really confusing if you insist on calling the group binary operator "multiplication" - please refer to it as "addition". It makes no difference logically. – Steve Jessop Jun 19 '11 at 01:23
  • And I'm not calling the group identity `0`. I'm calling it `e`. I'm calling the multiplicative identity of the field Z(2) `0`. [OOPS - no, I'm calling the *additive* identify of the field Z(2) `0`. I made the same error when I said, "The "scalar zero" is by definition the multiplicative identity of the field". I meant, the "scalar zero" is by definition the *additive* identity of the field. It's getting a bit late at night here]. – Steve Jessop Jun 19 '11 at 01:26
  • @Steve: OK, I accept that you have defined how to multiply an element of the group by a scalar 0 or 1. Now how do you define the "dot product" of two group elements to yield a scalar 0 or 1? (Given that the group elements do not have any "components"... Yet.) That is, say I give you two distinct group elements a and b. Define their "dot product" using only the given properties plus your "scalar times element" definition. (I think you need this to complete your construction; correct me if I am wrong.) – Nemo Jun 19 '11 at 02:00
  • I don't define their dot product. I don't need to in order to prove the isomorphism, because "dot product" is not part of the axiomatisation of a vector space. That said, after proving that what we're dealing with is (isomorphic to) a finite vector space over Z(2), the obvious dot product to define would be to take a basis of the vector space (I don't care which one), express `a` and `b` in terms of that basis, and then the dot product is defined to be the count of basis elements that have coefficient 1 in both decompositions (ie, the sum of the products of corresponding coefficients), mod 2. – Steve Jessop Jun 19 '11 at 02:07
  • @Steve: OK, I finally follow you. Interesting. The only place your construction uses the self-inverse assumption is in satisfying the "distribute scalar multiplication over vector addition" axiom, I think (1 + 1)v = v + v = 0v = e. Very pretty... I will update my answer. – Nemo Jun 19 '11 at 02:17
  • @Nemo: cool. I got slightly carried away at the end there, though. The "dot product" I defined follows the usual pattern for a dot product, but in fact that function doesn't form an inner product over a finite field. Usually inner products are only defined for fields over the real numbers (or bigger). – Steve Jessop Jun 19 '11 at 10:11
19

This is based on the simple fact that XOR of a number with itself results Zero.

and XOR of a number with 0 results the number itself.

So, if we have an array = {5,8,12,5,12}.

5 is occurring 2 times. 8 is occurring 1 times. 12 is occurring 2 times.

We have to find the number occurring odd number of times. Clearly, 8 is the number.

We start with res=0 and XOR with all the elements of the array.

int res=0; for(int i:array) res = res ^ i;

    1st Iteration: res = 0^5 = 5
    2nd Iteration: res = 5^8 
    3rd Iteration: res = 5^8^12
    4th Iteration: res = 5^8^12^5 = 0^8^12 = 8^12
    5th Iteration: res = 8^12^12 = 8^0 = 8
skmangalam
  • 359
  • 2
  • 8
6

The bitwise operators treat the bits inside an integer value as a tiny array of bits. Each of those bits is like a tiny bool value. When you use the bitwise exclusive or operator, one interpretation of what the operator does is:

  • for each bit in the first value, toggle the bit if the corresponding bit in the second value is set

The net effect is that a single bit starts out false and if the total number of "toggles" is even, it will still be false at the end. If the total number of "toggles" is odd, it will be true at the end.

Just think "tiny array of boolean values" and it will start to make sense.

Rick Sladkey
  • 33,988
  • 6
  • 71
  • 95
2

The definition of the XOR (exclusive OR) operator, over bits, is that:

0 XOR 0 = 0
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0

One of the ways to imagine it, is to say that the "1" on the right side changes the bit from the left side, and 0 on the right side doesn't change the bit on the left side. However, XOR is commutative, so the same is true if the sides are reversed. As any number can be represented in binary form, any two numbers can be XOR-ed together.

To prove it being commutative, you can simply look at its definition, and see that for every combination of bits on either side, the result is the same if the sides are changed. To prove it being associative, you can simply run through all possible combinations of having 3 bits being XOR-ed to each other, and the result will stay the same no matter what the order is.

Now, as we proved the above, let's see what happens if we XOR the same number at itself. Since the operation works on individual bits, we can test it on just two numbers: 0 and 1.

0 XOR 0 = 0
1 XOR 1 = 0

So, if you XOR a number onto itself, you always get 0 (believe it or not, but that property of XOR has been used by compilers, when a 0 needs to be loaded into a CPU register. It's faster to perform a bit operation than to explicitly push 0 into a register. The compiler will just produce assembly code to XOR a register onto itself).

Now, if X XOR X is 0, and XOR is associative, and you need to find out what number hasn't repeated in a sequence of numbers where all other numbers have been repeated two (or any other odd number of times). If we had the repeating numbers together, they will XOR to 0. Anything that is XOR-ed with 0 will remain itself. So, out of XOR-ing such a sequence, you will end up being left with a number that doesn't repeat (or repeats an even number of times).

Pawel Veselov
  • 3,996
  • 7
  • 44
  • 62
1

This has a lot of samples of various functionalities done by bit fiddling. Some of can be quite complex so beware.

What you need to do to understand the bit operations is, at least, this:

  • the input data, in binary form
  • a truth table that tells you how to "mix" the inputs to form the result

For XOR, the truth table is simple:

1^1 = 0
1^0 = 1
0^1 = 1
0^0 = 0

To obtain bit n in the result you apply the rule to bits n in the first and second inputs.

If you try to calculate 1^1^0^1 or any other combination, you will discover that the result is 1 if there is an odd number of 1's and 0 otherwise. You will also discover that any number XOR'ed with itself is 0 and that is doesn't matter in what order you do the calculations, e.g. 1^1^(0^1) = 1^(1^0)^1.

This means that when you XOR all the numbers in your list, the ones which are duplicates (or present an even number of times) will XOR to 0 and you will be left with just the one which is present an odd number of times.

Andrei
  • 4,880
  • 23
  • 30
0

As it is obvious from the name(bitwise), it operates between bits. Let's see how it works, for example, we have two numbers a=3 and b=4, the binary representation of 3 is 011 and of 4 is 100, so basically xor of the same bits is 0 and for opposite bits, it is 1. In the given example 3^4, where "^" is a xor symbol, will give us 111 whose decimal value will be 7. for another example, if you've given an array in which every element occurs twice except one element & you've to find that element. How can you do that? simple xor of the same numbers will always be 0 and the number which occur exactly once will be your output. because the output of any one number with 0 will be the same name number because the number will have set bits which zero don't have.