3

The following two C functions are equivalent:

unsigned f(unsigned A, unsigned B) {
  return (A | B) & -(A | B);
}
unsigned g(unsigned A, unsigned B) {
  unsigned C = (A - 1) & (B - 1);
  return (C + 1) & ~C;
}

My question is: why are they equivalent? What rules/transforms occur to g which transform it into f?

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • 3
    If two logical functions have the same truth table (which makes them equivalent), it does not mean that the rules transforming one function to another exist. Moreover, they can use different algebra (operators set). –  Aug 13 '14 at 06:06
  • Note also that these are not bitwise functions, as they contain arithmetic operators. – Paul R Aug 13 '14 at 06:13
  • I dont think they are equivalent , suppose A is 5 and B is 4, from fn f will return 0,, wheras fn g will return a non zero value. – Bas Aug 13 '14 at 06:20
  • @Bas, that case returns 1 from both f and g. – perreal Aug 13 '14 at 06:23
  • Oh, I am sorry , I took -(A|B) as ~(A|B) – Bas Aug 13 '14 at 06:25

1 Answers1

8

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

Community
  • 1
  • 1
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • @chux: Good point. I initially assumed that bit pattern produced in an unsigned value by unary `-` depends on the representation. But it doesn't. – AnT stands with Russia Aug 13 '14 at 15:53
  • Minor: "... contains a sole 1 bit in the position of the lowest 1 in both A and B." --> "lowest 1 in A or B.". The "and" used here in an English sense somewhat conflicts with the `A | B` operation. Hmmm - Even my suggestion looks awkward. – chux - Reinstate Monica Aug 13 '14 at 16:04