为什么在这种情况下,我的Java代码比我的C++;密码?

为什么在这种情况下,我的Java代码比我的C++;密码?,java,c++,benchmarking,microbenchmark,Java,C++,Benchmarking,Microbenchmark,我写了一个小的基准测试,在这个测试中,程序创建了108个二维std::vector结构的{float,float},然后求出它们长度的平方 这里是C++代码: #包括 #包括 #包括 #包括 #包括 使用名称空间std; 使用名称空间std::chrono; const int COUNT=功率(10,8); Vec类{ 公众: 浮动x,y; Vec(){} Vec(float x,float y):x(x),y(y){ 浮点len(){ 返回x*x+y*y; } }; int main(){

我写了一个小的基准测试,在这个测试中,程序创建了108个二维
std::vector
结构的
{float,float}
,然后求出它们长度的平方

这里是C++代码:

#包括
#包括
#包括
#包括
#包括
使用名称空间std;
使用名称空间std::chrono;
const int COUNT=功率(10,8);
Vec类{
公众:
浮动x,y;
Vec(){}
Vec(float x,float y):x(x),y(y){
浮点len(){
返回x*x+y*y;
}
};
int main(){
向量向量机;
对于(int i=0;i
    float sum = std::transform_reduce(
        std::execution::par_unseq,
        begin(vecs), end(vecs),
        0.f,
        std::plus<>{},
        [](auto&& x){
            return x.len();
        }
    );
float sum=std::transform\u reduce(
标准::执行::par_unseq,
开始(vecs),结束(vecs),
0.f,
std::plus{},
[](自动和&x){
返回x.len();
}
);

这明确地告诉C++编译器你在做什么,你可以使用额外的线程,每个循环迭代不依赖于其他,并且你想在<代码>浮点< /COD> S.< /P>中完成工作。 这确实意味着,与您要求的相比,加法可能会出现顺序错误,因此输出值可能不完全相同

一边是原始循环,另一边是无序添加的权限


进一步调查:

所以我旋转起来

在这篇文章中,我比较了有无强制矢量化和
-ffast math
。强制矢量化和
-ffast math
产生了相同的汇编代码

问题是累加器。将一次一个的内容添加到总和中,并进行所有IEEE舍入,得到的值与将它们N次累积到更高精度的浮点值中,然后将结果批量存储回浮点值不同

如果你做
-ffast math
你会得到2倍的速度和不同的累加。如果你用
双和
替换
浮点和
,你会得到as
--ffast math
和向量


基本上,clang向量化器无法在不违反精确浮点精度要求的情况下对总和的累积进行向量化。

我认为这样15%的差异并不显著。要回答这样一个问题,需要使用汇编代码,而JVM则更难做到这一点……因此,不必全部使用汇编代码详细信息(编译器版本、操作系统等)我想没有人能回答。可能是因为一个二进制运行32位代码,另一个运行64位代码?谢谢你的评论。两个程序确实都在64位模式下运行。使用reserve并没有提高性能。计数在两个程序中都是相同的。是的,正如上面的Makefile中所述,我确实使用了
-O3
@RoyVaron如果基准是整个程序的基准,reserve可能(肯定)会提高性能。在意识到
向量的填充实际上不在计时部分后,我删除了我的注释…我忘记了
transform\u reduce
甚至存在!属性
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu((总是内联))有多大区别
make?我希望编译器内联这一行函数regardles。您删除构造函数的事实是否重要?它使类的构造变得微不足道,因此这一定有点重要。@AyxanHaqverdili我只是在迭代删除“cruft”这可能会妨碍编译器知道
Vec
只是一些简单的二进制数据(可复制的很小等)。我怀疑这有什么关系。请注意,我只使用10^7个元素进行模拟,正如godbolt在要求10^8时所抱怨的那样。
pragma omp simd reduce(+:sum)
使用
-fopenmp
编译将允许编译器假装FP math与该缩减相关,而不必对整个文件使用
-ffast math
。另外请注意,使用多个累加器(SIMD向量的元素和多个SIMD向量)对于数值精度而言,这通常是一件好事。结果不同,因为它可能比原始标量版本的舍入误差更小,更接近成对求和。(/)。但通常情况下,
-ffast math
不会使结果更准确!