[英]C++ - Apply std::exp to an std::vector
有没有比简单地更快(从性能角度)的方法
std::vector<double> y;
y.reserve(x.size());
for(size_t i = 0; i < x.size(); ++i)
y.push_back(std::exp(x[i]));
如果您需要最接近的 ULP 的最大精度,这可能与您将要获得的一样快。
如果您可以接受一些近似误差,那么使用 SIMD 的方法要快得多。
令人惊讶的是, push_back
有一点开销,因为它实际上并不知道您预留了足够的空间,因此它总是需要检查。 由于此检查可以更改循环迭代之间的控制流,因此push_back
阻止编译器进行自动矢量化。
考虑这两个函数,第一个函数使用push_back
,而第二个函数就地修改副本(或移入值):
auto exp1(std::vector<double> const& xs) -> std::vector<double> {
auto ys = std::vector<double>{};
ys.reserve(xs.size());
for(auto x : xs){ ys.push_back(std::exp(x)); }
}
auto exp2(std::vector<double> xs) -> std::vector<double> {
for(auto & x : xs){ x = std::exp(x); }
return xs;
}
如果在 GCC 9.1 中编译,我们将查看程序集输出
gcc -std=c++17 -O3 -march=skylake-avx512
这是exp1
的内部循环(嵌入了相当多的额外代码,这些代码永远不会被执行,因为您已经reserve
d):
.L45:
add rbx, 8
vmovsd QWORD PTR [r14], xmm0
add r14, 8
cmp r12, rbx
je .L44
.L18:
vmovsd xmm0, QWORD PTR [rbx]
call exp
vmovsd QWORD PTR [rsp], xmm0
cmp rbp, r14
jne .L45
这是exp2
的:
.L53:
vmovsd xmm0, QWORD PTR [rbx]
add rbx, 8
call exp
vmovsd QWORD PTR [rbx-8], xmm0
cmp rbp, rbx
jne .L53
在实践中,它们基本相同,因为exp
很复杂,而且 GCC 不知道如何自动对其进行矢量化。 但是,请考虑在内循环中发生更简单的事情的情况:
auto sq1(std::vector<double> const& xs) -> std::vector<double> {
auto ys = std::vector<double>{};
ys.reserve(xs.size());
for(auto x : xs){ ys.push_back(x*x); }
}
auto sq2(std::vector<double> xs) -> std::vector<double> {
for(auto & x : xs){ x *= x; }
return xs;
}
这是sq1
的内部循环:
.L89:
vmovsd QWORD PTR [rsi], xmm0
add rbx, 8
add rsi, 8
mov QWORD PTR [rsp+24], rsi
cmp rbp, rbx
je .L72
.L75:
vmovsd xmm0, QWORD PTR [rbx]
mov rsi, QWORD PTR [rsp+24]
vmulsd xmm0, xmm0, xmm0
vmovsd QWORD PTR [rsp+8], xmm0
cmp rsi, QWORD PTR [rsp+32]
jne .L89
这是sq2
的。 请注意,它使用vmulpd
和ymm
寄存器,并且一次跳转 32 个字节而不是一次 8 个字节。
.L11:
vmovupd ymm0, YMMWORD PTR [rdx]
add rdx, 32
vmulpd ymm0, ymm0, ymm0
vmovupd YMMWORD PTR [rdx-32], ymm0
cmp rdx, rcx
jne .L11
当然,这个内循环片段有点误导:如果std::vector
的大小没有被 4 整除,它隐藏了大量用于处理剩余部分的代码。 不过,我的主要观点是是的,你实际上可以做得比reserve
+ push_back
好一点(当我第一次发现时,这让我很惊讶),如果我们不特别处理exp
会好得多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.