浮点加法与浮点乘法的相对速度是多少?

十年或两年前,写数字代码是值得的,以避免使用乘法和除法,而是使用加法和减法。 一个很好的例子是使用前向差异来评估多项式曲线,而不是直接计算多项式。

这仍然是这种情况,或者现代计算机体系结构提前到*,/不再比+慢多少倍, - ?

具体而言,我对在现代典型x86芯片上运行的编译C / C ++代码感兴趣,这些代码使用大量的板载浮点硬件,而不是试图在软件中执行FP的小型微代码。 我意识到流水线和其他架构增强功能会排除特定的周期数,但我仍然希望获得有用的直觉。


这也取决于教学组合。 你的处理器将有几个计算单元随时待命,如果它们全部都被填满,你将获得最大的吞吐量。 所以,执行一个循环的mul就像执行一个循环或增加一样快 - 但是如果表达式变得更复杂,这个循环不成立。

例如,采取这个循环:

for(int j=0;j<NUMITER;j++) {
  for(int i=1;i<NUMEL;i++) {
    bla += 2.1 + arr1[i] + arr2[i] + arr3[i] + arr4[i] ;
  }
}

对于NUMITER = 10 ^ 7,NUMEL = 10 ^ 2,两个数组都初始化为小正数(NaN慢得多),这需要6.0秒,在64位处理器上使用双精度。 如果我更换循环

bla += 2.1 * arr1[i] + arr2[i] + arr3[i] * arr4[i] ;

它只需要1.7秒...所以,因为我们“增加了”添加,所以muls基本上是免费的; 减少添加物有所帮助。 它变得更令人困惑:

bla += 2.1 + arr1[i] * arr2[i] + arr3[i] * arr4[i] ;

- 相同的mul / add分布,但现在常量被添加而不是乘以 - 需要3.7秒。 您的处理器可能被优化为更有效地执行典型的数值计算; 所以像摩尔和缩比和的总和就像它的总和一样好。 增加常量并不常见,所以速度较慢...

bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; /*someval == 2.1*/

再次需要1.7秒。

bla += someval + arr1[i] + arr2[i] + arr3[i] + arr4[i] ; /*someval == 2.1*/

(与初始循环相同,但没有昂贵的常量添加:2.1秒)

bla += someval * arr1[i] * arr2[i] * arr3[i] * arr4[i] ; /*someval == 2.1*/

(主要是muls,但增加了一个:1.9秒)

所以,基本上; 很难说哪个更快,但是如果你想避免瓶颈,更重要的是要有一个健全的组合,避免NaN或INF,避免添加常量。 不管你做什么,都要确保你测试并测试各种编译器设置,因为通常很小的更改只能改变它们。

更多情况:

bla *= someval; // someval very near 1.0; takes 2.1 seconds
bla *= arr1[i] ;// arr1[i] all very near 1.0; takes 66(!) seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; // 1.6 seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; //32-bit mode, 2.2 seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; //32-bit mode, floats 2.2 seconds
bla += someval * arr1[i]* arr2[i];// 0.9 in x64, 1.6 in x86
bla += someval * arr1[i];// 0.55 in x64, 0.8 in x86
bla += arr1[i] * arr2[i];// 0.8 in x64, 0.8 in x86, 0.95 in CLR+x64, 0.8 in CLR+x86

理论上这里的信息是:

英特尔®64和IA-32架构优化参考手册,附录C指导延迟和吞吐量

对于他们列出的每个处理器,FMUL的延迟非常接近FADD或FDIV。 在一些较旧的处理器上,FDIV比这个速度慢2-3倍,而在较新的处理器上,它与FMUL相同。

注意事项:

  • 我链接的文件实际上说,你不能在现实生活中依赖这些数字,因为如果处理器正确的话,处理器会按照它希望的那样做事。

  • 很有可能编译器会决定使用浮点乘法/除法的许多新指令集中的一个。

  • 这是一个复杂的文档,只能由编译器编写者阅读,我可能会误解它。 就像我不清楚为什么某些CPU的FDIV延迟数完全缺失。


  • 回答这个问题的最好方法是实际编写一个您需要执行的处理的基准/配置文件。 经验应尽可能超过理论。 特别是当它很容易达到。

    如果你已经知道数学的不同实现需要做,你可以写几个不同的数学代码转换,并查看你的性能高峰。 这将允许处理器/编译器生成不同的执行流来填充处理器管线,并为您的答案提供具体答案。

    如果您特别关注DIV / MUL / ADD / SUB类型指令的性能,您甚至可以在某些内联汇编中折腾来专门控制执行这些指令的哪些变体。 但是,您需要确保您保持多个执行单元的繁忙,以便了解系统的性能。

    此外,通过执行相同的程序,您可以比较处理器多种版本的性能,还可以考虑主板之间的差异。

    编辑:

    a +的基本架构完全相同。 所以他们在逻辑上采取相同的时间进行计算。 *另一方面,需要多层,通常由“全加器”构成以完成单个操作。 这样可以保证每个周期都可以发送一个*到管道,但是它的延迟比加/减电路要高。 fp /操作通常使用近似方法来实现,该方法随着时间的推移迭代收敛于正确答案。 这些类型的近似值通常通过乘法来实现。 所以对于浮点数,通常可以假设除法需要更长的时间,因为将乘法运算(这已经是大型电路和自身)“展开”到多个乘法器电路的流水线中是不切实际的。 仍然通过测试来衡量给定系统的性能。

    链接地址: http://www.djcxy.com/p/85647.html

    上一篇: What's the relative speed of floating point add vs. floating point multiply

    下一篇: SIMD (SSE) instruction for division in GCC