如果 x > y,则用 y 交换 x 的无分支版本?
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 %dn", 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);
的最快方法是确保为CPU生成正确的指令(例如,在80x86上给出CPU的xchg eax,ebx
,该指令没有分支,而不必等到值才知道)。<<<<)。/p>
正如其他人建议的那样,您可以尝试根据std::min()
和std::max()
。
但是不能保证。该语言只是缺少一种表达您想要的编译器的方法。
关于我可能提供的唯一其他非C 解决方案将是内联汇编,您可以精确地编写所需的说明。但是,使用内联装配会影响编译器对周围的代码的作用,并且可能会产生负面影响(例如,使用寄存器,注册溢出等)可能会抵消或否定任何预期的收益。
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 导入库可以跨dll版本工作吗
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- C++嵌套if语句,基本货币交换
- 在clang++预处理器中确定gcc工具链版本
- 码头化的C++应用程序是否向后兼容早期的内核版本
- shell排序中的交换和比较
- 不同的Visual Studio版本中缺少.dll
- 用符号版本替换对函数的所有调用
- luaL_dofile在已知良好的字节码上失败,可以使用未编译的版本
- 正在解码MSVC 32位版本的程序集(作业).没有手术做什么
- 排序时无法执行交换操作.我做的时候它会崩溃.为什么
- 我需要分发哪些版本的可再分发文件
- 通过交换元素使数组相同
- 如何使 std::sort 在 std::swap 和我的命名空间的模板化交换之间没有名称冲突?
- 为什么此代码上的排序算法不调用类的交换版本?
- 如果 x > y,则用 y 交换 x 的无分支版本?
- 为什么我的交换<字符串,字符串>比标准版本慢得多?
- 为什么两阶段查找无法选择"交换"的重载版本?
- 哪些std函数调用交换函数的用户实现版本