假设我们有一个经典的场景,我们需要找到数组的最大元素(仅限整数),但不是它的位置。以下 2 个代码示例(放置在“for”循环内)中哪一个在 CPU 上运行速度更快,哪一个在 GPU 上运行速度更快,为什么?
if( array[i] > max)
max = array[i];
和
max = 0.5 * ( a + b + abs(a-b)); //Where 'a' and 'b' refer to 'max' and 'array[i]'
此外,第二个代码块中真正困扰我的是“abs”函数调用。有没有办法只用算术表达式来计算一个数的绝对值?
最佳答案
我认为您确实想询问无分支与分支方式的m = max(m, array[i])
。 C 编译器已根据优化设置将 if()
版本编译为无分支代码(使用 cmov
)。它甚至可以自动矢量化为压缩比较或压缩最大函数。
您的 0.5 * abs()
版本显然很糟糕(比条件移动慢很多),因为它会转换为 double
并返回。而不是通过右移除以二。
查看 the Godbolt Compiler Explorer 上的 asm :
// auto-vectorizes to PMAXSD, or without SSE4.1, to pcmpgt / pand/por emulation of the same
int maxarray_if(int arr[], int n) {
int result = arr[0];
for (int i=0 ; i<n; ++i) {
int tmp = arr[i];
if (result < tmp)
result = tmp;
}
return result;
}
gcc 5.3 -O3 -march=haswell -mno-avx
自动矢量化内循环:
.L13:
add eax, 1
pmaxsd xmm0, XMMWORD PTR [rdx]
add rdx, 16
cmp r8d, eax
ja .L13
对比。 FP 版本:
... whole bunch of integer crap
cvtsi2sd xmm0, eax
mulsd xmm0, xmm1
cvttsd2si eax, xmm0
所以 FP 版本显然完全是垃圾。
对于任何目标架构,您都会得到类似的结果。与 double
之间的转换不会消失。 gcc 即使使用 -ffast-math
也能保持它。
关于在查找数组的最大元素时比较 2 种不同架构上的 2 种不同场景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37149330/