C++ 浮点计算的更改取决于编译器

C++ 浮点计算的更改取决于编译器,c++,c,floating-point,C++,C,Floating Point,当我运行完全相同的代码执行在Windows和Solaris上编译的完全相同的浮点计算(使用双精度)时,得到的结果略有不同 我知道由于舍入误差,结果不准确。然而,我希望舍入误差与平台无关,因此在两个平台上给出的结果是相同的(稍微不正确),但事实并非如此 这是正常的,还是我的代码中有另一个问题?在x86上,通常大多数计算都是以80位的数量进行的,除非被迫采用双精度。我所知道的大多数其他体系结构都以双精度进行所有计算(同样,除非另行重写) 我不知道您是否在SPARC或x86上运行Solaris,但如果

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

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


这是正常的,还是我的代码中有另一个问题?

在x86上,通常大多数计算都是以80位的数量进行的,除非被迫采用双精度。我所知道的大多数其他体系结构都以双精度进行所有计算(同样,除非另行重写)


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

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

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

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


<> P>最后,不同的C++语言实现可能会不同地实现浮点语义,所以你甚至可能从同一硬件的不同C++编译器获得不同的结果。

< P>我相信在Windows /x86下,你的代码将运行在已经设置为53位(双精度)的X87精度上,虽然我不确定这是什么时候开始的。在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时出现的一些问题:


如果您发布代码的测试用例会有所帮助。对于此类问题,测试用例的长度不应超过3-4行。如果是Solaris x86,则此80位表示可能仍然是差异的原因。如果使用(内置)x87数学协处理器;如果它使用的是较新的SSE向量单元,则它们是正常的64位双倍。默认情况下,GCC倾向于使用x87以与旧处理器兼容;任何其他编译器都会使用SSE单元,因为它即使对于非向量的东西也更快。@Brooks:谢谢!非常好的澄清。不客气!顺便说一下,是p这是谷歌首次对“gcc浮点错误”的搜索结果,它将告诉你人们遇到这个问题的频率!)这是可以修复的,将FPU控制字的PC字段设置为双精度(53位).Intel手册第8.1.5.2章。检查您的CRT实现是否有类似于_controlfp或_control87的内容。