1a. Expression x & -x
is a well-known "bit hack": it evaluates to a value that has all bits set to 0
except for one bit: the lowest 1
bit in the original value of x
. (Unless x
is 0
, of course.)
For example, in unsigned arithmetic: 5 & -5 = 1
, 4 & -4 = 4
etc.
2a. This immediately tells us what function f
does: by using |
operator it combines all 1
bits in A
and B
and then finds the lowest 1
in the combined value. In other words, the result of f
is a word that contains a sole 1
bit in the position of the lowest 1
in A
or B
.
1b. Expression (x + 1) & ~x
is a well-known "bit hack": it evaluates to all bits set to 0
except for the lowest 0
bit in the original value of x
. The lowest 0
bit in x
becomes the sole 1
in the resultant value. (Unless x
is all-1-bits, of course.)
For example, in unsigned arithmetic: (5 + 1) & -5 = 2
, (4 + 1) & -4 = 1
etc.
2b. Expression x - 1
replaces all trailing 0
bits in x
with 1
and replaces the lowest 1
in x
with 0
, keeping the rest of x
unchanged. Operator &
combines all 0
bits (just like operator |
combines all 1
bits). That means that (A - 1) & (B - 1)
will have its lowest 0
bit where the lowest 1
bit was in A
or B
.
3b. Per 1b, (C + 1) & ~C
replaces that lowest 0
with a lone 1
, zeroing out everything else.
That means that g
does the same thing as f
. Both functions find and return the lowest 1
bit between two input values. The result is always a power of 2 (or just 0). E.g. if at least one input value is odd, the result is 1.
I have an intuitive feeling (which could be wrong) that in order to build a formal transformation of one function into the other by applying additional operations to the existing expressions, one needs at least one of these functions to be "reversible" (is some semi-informal meaning of the term). Neither of these two looks sufficiently "reversible" to me...