use*_*112 2 c++ floating-point cpu double performance
a声明为double时,以下代码较慢,而不是int:
double a = 0;
int j[1000];
for(int i=0; i<1000; i++){
a += (i * j[i]);
}
Run Code Online (Sandbox Code Playgroud)
如果编译器选择不同的汇编指令而不是a声明为int时所选择的汇编指令会导致双精度加法的性能下降吗?
我试图了解CPU是否在运行时对单/双精度进行任何"转换",这在组装和成本执行时间中看不到?
让我们将循环中的表达式分解为各自的部分.为此,我们将重写代码,以便每行只有一个赋值和一个操作.从int版本开始时,它看起来如下所示:
// not depending on a
/* 1 */ auto t1 = j[i];
/* 2 */ auto t2 = i * j
// depending on decltype(a)
/* 3 */ decltype(a+t2) t3 = static_cast<decltype(a+t2)>(t2);
/* 4 */ decltype(a+t3) t4 = static_cast<decltype(a+t3)>(a);
/* 5 */ a = t3 + t4;
Run Code Online (Sandbox Code Playgroud)
前两个操作根本不依赖于类型a,并且在任何一种情况下都会完全相同.
但是,从操作3开始,存在差异.原因是添加a和t2编译器必须首先将它们转换为通用类型.在a整数的情况下,操作3和4什么都不做(int+ intyield int,所以两个强制转换都将ints 转换为ints).但是,在aa 的情况下double,t2必须在添加之前转换为double(int+ double给出double).
这意味着操作5中的添加类型也不同:它可以是一个int或double另外一个.忽略一个明显的方面,即a double通常是a的两倍int,这意味着计算机此时需要做一些不同的事情.
当使用优化编译器为现代x64机器编译该程序时,应该注意,当按原样说明时,整个程序可以被优化掉.假设这没有发生并且您的编译器不应用任何非法优化,并且您可以使用未初始化的变量(元素j)引入的UB ,可能会发生以下情况:
// not depending on a
MOV EAX, i // copy i to EAX register
IMUL j[i] // EAX = EAX * j[i] (high 32 bits are stored in EDX and ignored)
// if a is int
ADD a, EAX // integer addition: a += EAX
// else if a is double
CVTSI2SD XMM0, EAX // convert the multiplication result to double
ADDPD a, XMM0 // double addition: a += XMM0
// endif
Run Code Online (Sandbox Code Playgroud)
一个好的编译器会稍微展开循环并交错其中的一些,因为循环限制是已知的.正如您所看到的,操作至少有两倍的增加,以及依赖链的指令.此外,第二个版本中的指令比第一个版本中的单个指令慢.
虽然我确信第二个版本可以在一个更高效的版本中声明,但应该注意的是ADD,第一个版本的整数是几乎任何CPU上最快的操作之一,并且通常比它的浮点数更快.
因此,回答您的问题:CPU确实执行浮点和整数之间的转换 - 这些转换在程序集中可见并且具有(可能很大的)运行时成本.
既然您也询问了单精度,那么让我们来看看使用时会发生什么float:
// not depending on a
MOV EAX, i // copy i to EAX register
IMUL j[i] // EAX = EAX * j[i] (high 32 bits are stored in EDX and ignored)
// if a is float
CVTSI2SS XMM0, EAX // convert the multiplication result to float
ADDPS a, XMM0 // float addition: a += XMM0
Run Code Online (Sandbox Code Playgroud)
该组件不显示显著差异(我们刚刚更换的两个D用于double与S供single).而且,有趣的是,性能上的差异也会很小(例如,Haswell核心将转换为1μop,而转换为浮动,而加法本身表现出相同的性能).
为了验证我的声明,我已经运行了2000000次循环,并确保a没有优化.结果是:
int : 601.1 ms
float : 2567 ms
double: 2593 ms
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
130 次 |
| 最近记录: |