我正在寻找一种表达式,它使我能够使用以下属性进行编写:

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

没有乘法/分支,尽可能高效。

乍一看 x ^ 0x80000000 似乎是一个候选,但是当 x 为 0 时它不起作用。

最佳答案

好的,我终于想出了如何有效地做到这一点:

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;
}

上述这些函数返回 -sgn(x) y is -1 sgn(x) 否则。

或者,如果我们只需要对除 -2^31(最小无符号 int 值)之外的每个值进行处理,以保留绝对值的好处,则这是根据变量 y 翻转符号的函数:
int f(int x, int y) {
    return (x ^ y) - y; // returns -x for y == -1, x otherwise
}

派生 :
-x == ~x + 1 == (x ^ 0xFFFFFFFF) + 1 == (x ^ -1) + 1 == (x ^ -1) - (-1)。用 y 替换 -1,我们得到一个双变量公式,它有一个有趣的属性,如果 y 设置为 0,则返回不变的 x,因为 (x ^ 0) 和减去 0 都不会改变结果。现在的极端情况是当这个公式不起作用时 x 是否等于 0x8000000。这可以通过应用 sgn(x) 函数来解决,所以我们有 (sgn(x) ^ y) - y) 。最后,我们用不使用分支的众所周知的公式替换 sgn(x) 函数。

关于performance - 如何在没有乘法/分支的情况下使用一些常量和运算符翻转整数值的符号,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4866187/

10-12 13:28