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

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

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

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

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

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

我相信在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

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

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

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

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