performance - 如何在没有乘法/分支的情况下使用一些常量和运算符翻转整数值的符号

标签 performance integer bit-manipulation flip sign

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

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 是 -1sgn(x) 否则。

或者,如果我们只需要为除 -2^31(最小无符号整数值)之外的每个值工作,为了保留绝对值,这是翻转符号的函数,具体取决于变量 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/

相关文章:

java - 将 List<List<Integer>> 转换为 int[][]

java - 将 'bits' 写入 C++ 文件流

sql - 为什么 SQL Server 突然决定使用这么可怕的执行计划?

javascript - jQuery 性能全屏淡入淡出

java - 比较 Spark 中的两个数据帧(性能)

performance - 我看不到用于测量功耗的 perf 的 power/energy-cores 选项

java - 我可以以某种方式排除或过滤掉 java 中 Collections.Min/Collections.Max 中的值吗?

c# - 在 C# 中,如何提取构成 UInt128 的两个 UInt64 值?

java - 移动负 BigInteger 值 - Java

c - int 中的 1 保证在 C 中是 00...001 吗?