^
is XOR, a bitwise operation. On a single bit, the rules are 0 ^ 0 = 0
, 0 ^ 1 = 1
, 1 ^ 0 = 0
, and 1 ^ 1 = 0
, and you simply extend perform it on corresponding bits when dealing with multi-bit values. The name is short for "exclusive or", and comes from the fact that A ^ B
is 1
if and only if either A or B is 1
, not both. But, it's more interesting to talk about its other name, ⊕. ⊕ is + but slightly different. You'll notice that the rules for ⊕ are similar to the rules for addition: 0 + 0 = 0
, 0 + 1 = 1
, 1 + 0 = 1
, and 1 + 1 = 10
. ⊕ is +, except 1 ⊕ 1 = 0
; that is, ⊕ is +, except without carrying. This holds for multiple bits: 011 + 001 = 100
, because you carry a 1
out of the ones place into the twos place, and then carry a 1
again into the fours place. Then, 011 ⊕ 001 = 010
, because you just don't carry.
Now, when doing real addition, when do you carry? In binary, the answer is very simple: you carry a 1
into the next place when there are two 1
s in a given place. This is easily understood as a bitwise AND, &
. 1 & 1 = 1
, and 0
otherwise. For 011 + 001
, addition without carrying gives 011 ⊕ 001 = 010
, and we can tell we need to carry a 1
out of the ones place because 011 & 001 = 001
. The shifting in (a & b) << 1
turns a number "where do I need to carry from?" into "where do I need to add carries?": (011 & 001) << 1 = 010
; I need to add a carry bit in the twos place.
So, in getSum
, we want to know a + b
. We compute the addition without carrying with a ^ b
, and we find where we need to add carry bits with (a & b) << 1
. Now, we just need to add those two together. Well, we already have a function for adding numbers together; it's called getSum
. So, we basically just write function getSum(a, b) { return getSum(a ^ b, (a & b) << 1); }
, except we make sure to short-circuit if there is nothing to carry, saving us from infinite recursion.