Adding an excellent answer to FatalError, the string return f(b)^f(a-1); could be better explained. In short, this is because XOR has these wonderful properties:
- He is associative . Put the brackets wherever you want.
- It is commutative - it means that you can move operators (they can "commute")
Here and in action:
(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
Like this:
a ^ b = c c ^ a = b
Add and propagate two examples of other associative / commutative operators, but they do not change themselves. So why are these properties important? Well, a simple route is to expand it into what it really is, and then you can see these properties at work.
First we define what we want and call it n:
n = (a ^ a+1 ^ a+2 .. ^ b)
If this helps, think of XOR (^) as if it were an addition.
Let it also define a function:
f(b) = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b
b greater than a , so just reliably dropping a few extra brackets (which we can, because it is associative), we can also say the following:
f(b) = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)
This simplifies:
f(b) = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b) f(b) = f(a-1) ^ n
Then we use this reversal property and commutativity to give us the magic line:
n = f(b) ^ f(a-1)
If you think of XOR as an add-on, you would drop it. XOR is XOR, what to add to subtract!
How do I come up with this myself?
Remember the properties of logical operators. Work with them almost like adding or multiplying, if that helps. It feels unusual that both (&), xor (^) and or (|) are associative, but they are!
First, launch a naive implementation, look for patterns in the output, and then start searching for rules that confirm that the pattern is correct. Simplify your implementation even further and repeat. This is probably the route that the original creator took, emphasized by the fact that it is not completely optimal (i.e., uses the switch statement, not the array).