[英]Branchless version of swapping x with y if x > y?
假设x
和y
是有符号整数,是否有一些超级有效的技巧可用于实现:
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);
}
如果在此操作之后将x
和y
写入内存,则可以使用写入动态内存位置而不是条件跳转。 例如,对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.