浮点计算根据编译器而变化

时间:2010-03-04 01:12:32

标签: c++ c floating-point

当我运行完全相同的代码执行在Windows和Solaris上编译的完全相同的浮点计算(使用双精度)时,我得到的结果略有不同。

我知道由于舍入错误导致结果不准确。但是我希望舍入错误与平台无关,从而在两个平台上给出相同(略微不正确)的结果,但事实并非如此。

这是正常的,还是我的代码中还有其他问题?

3 个答案:

答案 0 :(得分:6)

在x86上,通常大多数计算都是以80位数量进行的,除非另外强制为双精度。我所知道的大多数其他架构都是以双精度进行所有计算(同样,除非另有覆盖)。

我不知道你是在SPARC还是x86上运行Solaris,但如果是前者,那么我非常怀疑这是造成差异的原因。

答案 1 :(得分:2)

我相信在Windows / x86下,你的代码将以x87精度已经设置为53位(双精度)运行,尽管我不确定它何时被设置。在Solaris / x86上,x87 FPU很可能使用其默认精度64位(扩展精度),因此存在差异。

您可以执行一项简单的检查来检测正在使用的精度(53位或64位):尝试计算类似1e16 + 2.9999的内容,同时小心避免编译器常量折叠优化(例如,定义一个单独的add函数来执行添加,并关闭可能内联函数的任何优化。当使用53位精度(SSE2,或双精度模式下的x87)时,这给出1e16 + 2;当使用64位精度(扩展精度模式下为x87)时,这给出1e16 + 4.后一个结果来自一个称为“双舍入”的效果,其中加法的结果首先舍入为64位,然后舍入为53位。 (直接在Python中进行此计算,我在32位Linux上获得1e16 + 4,在Windows上获得1e16 + 2,原因完全相同。)

这是一篇非常好的文章(远远超出了经常引用的Goldberg的“每个计算机科学家应该知道的......”),它解释了使用x87 FPU时出现的一些问题:

http://hal.archives-ouvertes.fr/docs/00/28/14/29/PDF/floating-point-article.pdf

答案 2 :(得分:1)

您的问题的主题表明它可能取决于编译器。它可能,但你在不同硬件上运行的事实(假设你的Solaris不是x86)表明这种差异的可能性更大 - 硬件本身的差异。

不同的硬件平台可能使用完全不同的硬件设备(FPU,CPU)来执行浮点计算,从而得到不同的结果。

此外,FPU单元通常可通过某些持久性设置进行配置,如无限模型,舍入模式等。不同的硬件可能具有不同的默认设置。编译器通常会生成在程序启动时初始化FPU的代码,初始设置也可能不同。

最后,C ++语言的不同实现可能会以不同方式实现浮点语义,因此您甚至可能从同一硬件的不同C ++编译器获得不同的结果。