x86 4字节浮点数与8字节双字节(长对长)?

时间:2010-11-12 09:10:09

标签: c++ x86 floating-point double

我们有一个测量数据处理应用程序,目前所有数据都保存为C ++ float,这意味着我们的x86 / Windows平台上有32bit / 4byte。 (32位Windows应用程序)。

由于精度正在成为一个问题,因此一直在讨论转向另一种数据类型。目前讨论的选项是切换到double(8字节)或在__int64(8字节)之上实现固定的十进制类型。

甚至讨论了使用__int64作为基础类型的固定小数解决方案的原因是有人声称double性能(仍)明显比处理float更差,而且我们可能会看到使用本机整数类型存储数字的显着性能优势。 (注意,我们确实可以使用固定的小数精度,尽管代码显然会变得更复杂。)

显然我们最终需要进行基准测试,但是我想问一下,加倍的声明是否会让现代处理器看到真相?我想对于大型阵列双打可能会使缓存命中更加浮动,但是否则我真的看不出它们在性能上会有什么不同?

7 个答案:

答案 0 :(得分:5)

这取决于你做了什么。 double上的加法,减法和乘法与当前x86和POWER架构处理器上float上的加法,减法和乘法一样快。使用双参数时,除法,平方根和超越函数(exp,log,sin,cos等)通常明显较慢,因为它们的运行时间取决于所需的精度。

如果你去固定点,乘法和除法需要使用长整数乘法/除法指令来实现,这些指令通常比double上的算术慢(因为处理器的优化程度不高)。更重要的是,如果你在32位模式下运行,需要从几个32位长的乘法中合成长64位乘以128位结果!

缓存利用率在这里是一个红色的鲱鱼。 64位整数和双精度大小相同 - 如果你需要超过32位,无论如何你都会吃掉这个惩罚。

答案 1 :(得分:4)

查一查。英特尔和英特尔都在其网站上的免费PDF文档中公布了CPU的指令延迟。

但是,大部分,性能不会有显着差异,或者有几个原因:

  • 当使用x87 FPU而不是SSE时,所有浮点运算在内部以80位精度计算,然后舍入,这意味着实际计算对于所有浮点类型同样昂贵。唯一的成本实际上是与内存相关的(就CPU缓存和内存带宽使用而言,这只是float vs double中的一个问题,但如果你不重要则无关紧要与int64
  • 比较
  • 有或没有SSE,几乎所有的浮点运算都是流水线的。使用SSE时,double指令可能(我还没有看过)具有比其float等效时间更长的延迟,但吞吐量是相同的,所以应该可以用doubles来实现类似的性能。

也不是定点数据类型实际上也会更快。它可能,但在某些操作后保持此数据类型一致的开销可能超过节省。浮点运算在现代CPU上相当便宜。它们有一些延迟,但如前所述,它们通常是流水线的,可能会隐藏这个成本。

所以我的建议:

  1. 写一些快速测试。写一个执行大量浮点运算的程序并不难,然后测量double版本相对于float版本的速度慢一点。
  2. 在手册中查找,并亲自了解floatdouble计算之间是否存在显着的性能差异

答案 2 :(得分:3)

我很难理解基本原理“比浮动慢两倍我们将使用64位int”。猜测性能一直是需要大量经验的黑色艺术,在今天的硬件上,考虑到要考虑的因素的数量,它甚至更糟。即使测量也很困难。我知道有几个案例,其中微观基准用于一个解决方案,但在上下文测量中显示另一个更好。

首先要注意的是,解释所声称的浮动性能比浮点性能慢的两个因素在这里并不相关:所需的带宽与双倍的64位int相同,而SSE2向量化将有利于双倍...

然后考虑比使用整数计算会增加整数寄存器和计算单元的压力,显然浮点数将保持不变。 (我已经看到过在double中进行整数计算的情况是由于增加的计算单位而获胜)

所以我怀疑滚动你自己的定点运算比使用double更有利(但我可能会被措施显示错误。)

答案 3 :(得分:2)

实施64个固定点并不是很有趣。特别是对于更复杂的函数,如Sqrt或对数。对于像添加这样的简单操作,整数可能会更快一些。而且你需要处理整数溢出。并且在实现舍入时需要小心,否则错误很容易累积。

我们在C#项目中实现了固定点,因为我们需要确定性,而.net上的浮点不能保证。这是相当痛苦的。一些公式包含x^3 bang int溢出。除非你有非常令人信服的理由,否则使用float或double而不是fixedpoint。

来自SSE2的SIMD指令进一步使比较复杂化,因为它们允许同时对多个浮点数(4个浮点数或2个双精度数)进行操作。我会使用double并尝试利用这些说明。所以double可能会比浮点数慢得多,但与int相比很难,而且我更喜欢浮点数/双倍超过固定点是大多数场景。

答案 4 :(得分:1)

测量而不是猜测总是最好的。是的,在许多体系结构上,double上的计算处理数据的两倍,因为float上的计算(和long double s的计算速度仍然较慢)。但是,正如其他答案和对此答案的评论所指出的那样,x86架构不遵循与ARM处理器,SPARC处理器等相同的规则。在x86 float s上,{{1 s和double都被转换为long double s进行计算。我应该知道这一点,因为转换导致x86结果比SPARC更准确,并且Sun经历了很多麻烦来获得Java的不太准确的结果,sparking some debate(注意,该页面是从1998年开始的,事情从此改变了。)

此外,long double的计算内置于CPU中,其中固定十进制数据类型的计算将用软件编写,并且可能更慢。

您应该能够找到一个像样的固定大小的十进制库并进行比较。

答案 5 :(得分:0)

使用各种SIMD指令集,您可以以相同的成本执行4个单精度浮点运算,基本上您可以将4个浮点数打包到一个128位寄存器中。当切换到双打时,你只能将2个双打打包到这些寄存器中,因此你只能同时进行两次操作。

答案 6 :(得分:0)

正如很多人所说的,如果double是一个选项,64位int可能不值得。至少在SSE可用时。这可能在各种微控制器上有所不同,但我想这不是你的应用程序。如果在长浮点数中需要额外的精度,你应该记住this operation is sometimes problematic有浮点数和双精度数,并且在整数上更精确。