繁体   English   中英

如果x> y,用y交换x的无分支版本?

[英]Branchless version of swapping x with y if x > y?

假设xy是有符号整数,是否有一些超级有效的技巧可用于实现:

if (x < y) {
    std::swap(x, y);
}

我可以立即想到使用c = x < y的解决方案,然后将x分配给c * x + (1 - c) * y等,但这种方法会发出乘法指令,我想避免。 有没有办法单独摆弄小玩意儿?

编辑:只是澄清我真正关心的是试图摆脱由if引起的分支。 换句话说,我知道做交换的XOR技巧,但那不是我要问的。

我不确定,这是你的代码,但这是无分支解决方案:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
  int a = atoi(argv[1]);
  int b = atoi(argv[2]);
  int c = a - b;
  c &= c >> 31; // SXT for signed int
  a -= c;
  b += c;
  printf("Result: %d %d\n", a, b);
}

如果在此操作之后将xy写入内存,则可以使用写入动态内存位置而不是条件跳转。 例如,对a[0], a[1]进行排序:

int x = a[0];
int y = a[1];
a[x >= y] = x;
a[y > x] = y;

如果您需要立即读取值,那么它可能比可预测的分支更慢,但它可能取决于处理器。

实现交换的最有效方法是识别您具有与名称关联的名称和数据,并且可以交换名称而不是交换数据。

例如,编译器可以转换为:

if (x < y) {
    std::swap(x, y);
}
do_something(x, y);
return x;

..到这个:

if (x < y) {
    // Names of "x" and "y" swapped in subsequent code
    do_something(y, x);
    return y;
} else {
    do_something(x, y);
    return x;
}

当然,交换名称而不是交换数据通常是免费的(因为性能),因为你实际上并没有交换任何东西。

现代CPU完全相同的技巧。

特别; CPU具有寄存器,寄存器是与数据相关联的名称。 对于像xchg eax,ebx (80x86)这样的指令,CPU只会交换寄存器名称而不会移动数据。 这意味着当任何寄存器中的数据尚未知道时,CPU可以进行交换(例如,因为它仍在被前一条指令计算或获取)。

换一种说法; 实现std::swap(x, y);的最快方法std::swap(x, y); 是为了确保为CPU生成正确的指令(例如,为了给CPU一个xchg eax,ebx在80x86上,它没有分支,也不必等到值已知)。

正如其他人所建议的那样,您可以尝试用std::min()std::max()重写代码。

但是没有保证。 该语言缺乏一种表达你想要的编译器的方法。

关于我可能提供的唯一其他非C ++解决方案是内联汇编,您可以在其中精确编写所需的指令。 但是,使用内联汇编会影响编译器对其周围的代码执行的操作,并且可能会产生负面影响(例如,寄存器的低效使用,寄存器溢出等),这可能会抵消或否定任何预期的收益。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM