Search code examples
performanceintegerbit-manipulationflipsign

How to flip the sign of an integer value using some constant and operator(s) without multiplication/branching


I am looking for an expression which would enable me to write with the following properties:

f(x, SOME_CONSTANT) -> returns -x (or any negative value)
f(x, SOME_CONSTANT2) -> returns x (or any positive value)
f(0, SOME_CONSTANT) -> returns 0
f(0, SOME_CONSTANT2) -> returns 0

without multiplication/branching, as efficient as possible.

At first glance x ^ 0x80000000 seems like a candidate, but it doesn't work when x is 0.


Solution

  • Ok, I finally figured out how to do this efficiently:

    Java:

    int f(int x, int y) {
      return (((x >> 31) | ((unsigned)-x >> 31)) ^ y) - y;
    }
    

    C/C++:

    int f(int x, int y) {
      return (((x > 0) - (x < 0)) ^ y) - y;
    }
    

    These above functions return -sgn(x) y is -1 and sgn(x) otherwise.

    Or, if we just need to work for every value other then -2^31 (minimum unsigned int value), with the benefit of preserving the absolute value, this is the function which flips the sign, depending on the variable y:

    int f(int x, int y) {
        return (x ^ y) - y; // returns -x for y == -1, x otherwise
    }
    

    The derivation: -x == ~x + 1 == (x ^ 0xFFFFFFFF) + 1 == (x ^ -1) + 1 == (x ^ -1) - (-1). Substituting -1 with y, we obtain a two-variable formula which has an interesting property that returns unchanged x if y is set to 0, because neither (x ^ 0) nor subtracting 0 changes the result. Now the corner case is if x is equal to 0x8000000 when this formula doesn't work. This can be fixed by applying the sgn(x) function, so we have (sgn(x) ^ y) - y). Finally, we replace the sgn(x) functions with the well-known formulas which do not use branching.