交换值的最有效方法c ++
most efficient way of swapping values c++
我想知道在操作方面最有效的交换整数的方法是在 C++ 中,为什么?是这样的:
int a =..., b = ...;
a = a + b;
b = a - b;
a = a - b;
比使用临时文件更有效?还有其他更有效的方法吗? (不只是要求交换整数的其他方法)为什么它们会更有效率?
最好的方法是相信你的编译器和使用C++标准库函数。它们是为彼此设计的。
std::swap
会赢。
您可以对 int
使用 XOR 交换(不需要临时),但现在它的性能仍然不如 std::swap
。
赋值总是比算术运算快。
C++ implementation 对于 std::swap 是
template<typename T> void swap(T& t1, T& t2) {
T temp = std::move(t1); // or T temp(std::move(t1));
t1 = std::move(t2);
t2 = std::move(temp);
}
所以使用临时变量比做算术技巧要好。
使用 std::swap 更好,因为 在编程中重新发明轮子从来都不是一个好主意
#include <iostream>
using namespace std;
void swap(int &a, int &b){
b = (a+b) - (a=b);
}
int main() {
int a=1,b=6;
swap(a,b);
cout<<a<<b;
return 0;
}
在我的例子中,std::swap
比下面的慢 5%(均采用 O3 优化)。通常,std::swap() 函数调用复制构造函数可能总是比只复制部分内存慢。
#include <cstring>
size_t objectSize = sizeof(Object);
char temp[objectSize];
loop {
loop {
memcpy(temp, a, objectSize);
memcpy(a, b, objectSize);
memcpy(b, temp, objectSize);
}
}
编辑:使用堆栈而不是堆内存分配。
最有效的方法是不要尝试自己做。
这真的取决于 why/were 你想这样做。在 C++ 中自作聪明并编写晦涩难懂的代码只会降低编译器正确优化它的机会。
假设我们使用您写的 ± 方式:
首先必须从内存中加载值 a 和 b。
然后你正在做 3 个算术运算来“交换”它们的内容。
最后,这 2 个值必须再次存储在内存中。
(不会使用实际的汇编代码,因为我不太熟悉它,而且这个伪汇编更容易理解这个概念)
load a into register rA
load b into register rB
add rB to rA and store in rA
subtract rB from rA and stor in rB
subtract rB from rA and store in rA
store register rA to memory b
store register rB to memory a
如果编译器完全按照您的要求执行(很可能他会忽略它并使其变得更好),那将是:
2 个加载,3 个简单的数学函数,2 个存储 - 7 个操作。
它还可以做得更好,因为 addition/subtraction 可以用内存中的 1 个值来完成。
load 'a' into register rA
add b to rA and store in rA
subtract b from rA and store in rB
subtract rB from rA and store in rA
store rA to a
store rB to b
如果我们使用额外的 tmp 变量:
int a =..., b = ...;
int tmp = a;
a = b;
b = tmp;
编译器可能会认识到“tmp”只是一个临时变量,仅用于交换 2 个值,因此它不会为其分配内存位置 btu 仅使用寄存器。
在那种情况下,它会做的是:
load a into register rA
load b into register rB
store register rA to memory b
store register rB to memory a
只有 4 次操作 - 基本上它可以做到的最快,因为您需要加载 2 个值并且您需要存储 2 个值,除此之外别无其他。
(对于现代 nx86_64 处理器,没有命令可以只交换内存中的 2 个值 - 其他架构可能有它并且在这种情况下甚至更快)。
执行这些算术运算(或 xor 技巧)是一个很好的练习,但在现代 x86 CPU 上,除了最基本的编译器之外,它不会以任何形式“更有效”。
它将使用同样多的寄存器,同样数量的变量内存,但需要更多的指令来完成同样的工作。
一般来说,您不应该试图超越编译器,除非您已经检查了您的代码、对其进行了测试和基准测试,并且发现生成的程序集并不尽如人意。
但几乎不需要达到那个级别进行优化,您的时间最好花在查看大图上。
我想知道在操作方面最有效的交换整数的方法是在 C++ 中,为什么?是这样的:
int a =..., b = ...;
a = a + b;
b = a - b;
a = a - b;
比使用临时文件更有效?还有其他更有效的方法吗? (不只是要求交换整数的其他方法)为什么它们会更有效率?
最好的方法是相信你的编译器和使用C++标准库函数。它们是为彼此设计的。
std::swap
会赢。
您可以对 int
使用 XOR 交换(不需要临时),但现在它的性能仍然不如 std::swap
。
赋值总是比算术运算快。
C++ implementation 对于 std::swap 是
template<typename T> void swap(T& t1, T& t2) {
T temp = std::move(t1); // or T temp(std::move(t1));
t1 = std::move(t2);
t2 = std::move(temp);
}
所以使用临时变量比做算术技巧要好。
使用 std::swap 更好,因为 在编程中重新发明轮子从来都不是一个好主意
#include <iostream>
using namespace std;
void swap(int &a, int &b){
b = (a+b) - (a=b);
}
int main() {
int a=1,b=6;
swap(a,b);
cout<<a<<b;
return 0;
}
在我的例子中,std::swap
比下面的慢 5%(均采用 O3 优化)。通常,std::swap() 函数调用复制构造函数可能总是比只复制部分内存慢。
#include <cstring>
size_t objectSize = sizeof(Object);
char temp[objectSize];
loop {
loop {
memcpy(temp, a, objectSize);
memcpy(a, b, objectSize);
memcpy(b, temp, objectSize);
}
}
编辑:使用堆栈而不是堆内存分配。
最有效的方法是不要尝试自己做。 这真的取决于 why/were 你想这样做。在 C++ 中自作聪明并编写晦涩难懂的代码只会降低编译器正确优化它的机会。
假设我们使用您写的 ± 方式: 首先必须从内存中加载值 a 和 b。 然后你正在做 3 个算术运算来“交换”它们的内容。 最后,这 2 个值必须再次存储在内存中。 (不会使用实际的汇编代码,因为我不太熟悉它,而且这个伪汇编更容易理解这个概念)
load a into register rA
load b into register rB
add rB to rA and store in rA
subtract rB from rA and stor in rB
subtract rB from rA and store in rA
store register rA to memory b
store register rB to memory a
如果编译器完全按照您的要求执行(很可能他会忽略它并使其变得更好),那将是: 2 个加载,3 个简单的数学函数,2 个存储 - 7 个操作。
它还可以做得更好,因为 addition/subtraction 可以用内存中的 1 个值来完成。
load 'a' into register rA
add b to rA and store in rA
subtract b from rA and store in rB
subtract rB from rA and store in rA
store rA to a
store rB to b
如果我们使用额外的 tmp 变量:
int a =..., b = ...;
int tmp = a;
a = b;
b = tmp;
编译器可能会认识到“tmp”只是一个临时变量,仅用于交换 2 个值,因此它不会为其分配内存位置 btu 仅使用寄存器。 在那种情况下,它会做的是:
load a into register rA
load b into register rB
store register rA to memory b
store register rB to memory a
只有 4 次操作 - 基本上它可以做到的最快,因为您需要加载 2 个值并且您需要存储 2 个值,除此之外别无其他。 (对于现代 nx86_64 处理器,没有命令可以只交换内存中的 2 个值 - 其他架构可能有它并且在这种情况下甚至更快)。
执行这些算术运算(或 xor 技巧)是一个很好的练习,但在现代 x86 CPU 上,除了最基本的编译器之外,它不会以任何形式“更有效”。 它将使用同样多的寄存器,同样数量的变量内存,但需要更多的指令来完成同样的工作。 一般来说,您不应该试图超越编译器,除非您已经检查了您的代码、对其进行了测试和基准测试,并且发现生成的程序集并不尽如人意。
但几乎不需要达到那个级别进行优化,您的时间最好花在查看大图上。