为什么std::inner_product比朴素实现慢?

3
这是我天真的点积实现方式:
float simple_dot(int N, float *A, float *B) {
    float dot = 0;
    for(int i = 0; i < N; ++i) {
    dot += A[i] * B[i];
    }

    return dot;
}

这是使用C++库的代码:

float library_dot(int N, float *A, float *B) {
    return std::inner_product(A, A+N, B, 0);
}

我运行了一些基准测试(代码在这里https://github.com/ijklr/sse),发现库的版本要慢得多。我的编译器标志是-Ofast -march=native

5
使用0.0f作为初始值。 - Kerrek SB
如果您在调用inner_product时将0更改为0f,会发生什么? - NathanOliver
1
@NathanOliver:编译器错误,因为“f”不是有效的八进制数字。 - Kerrek SB
你是否比较过你的两个算法在非平凡输入下是否产生相同的结果? - Kerrek SB
你试过使用std::transform_reduce吗?你甚至可以使用非顺序执行策略来进行向量化处理。 - wcochran
显示剩余7条评论
1个回答

8
你的两个函数并不是做同样的事情。该算法使用一个累加器,其类型是从初始值0推导出来的,而int是你这种情况下的类型。将浮点数累加到整型中不仅耗时更长,而且产生的结果也不同。
与你的原始循环代码相当的代码是使用初始值0.0f,或等价地使用float{}
(请注意,std::accumulate在这方面非常相似。)

谢谢。这很有帮助! - ijklr
GCC不会展开循环,而-funroll-loops也无法打破依赖链。Clang展开4次,这非常好。因此,至少在GCC中,std::inner_product并不是最优的,即使使用reductions也必须手动进行优化。 - Z boson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接