Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使SUN上的gcc以与Linux中相同的方式计算浮点_Linux_Floating Point_Solaris - Fatal编程技术网

如何使SUN上的gcc以与Linux中相同的方式计算浮点

如何使SUN上的gcc以与Linux中相同的方式计算浮点,linux,floating-point,solaris,Linux,Floating Point,Solaris,我有一个项目,我必须用双变量进行一些数学计算。 问题是我在SUN Solaris 9和Linux上得到的结果不同。 有很多方法(在这里和其他论坛中解释)可以让Linux像Sun一样工作,但不是相反。 我不能触摸Linux代码,所以只有SUN可以更改。 有没有办法让SUN像Linux一样运行 我运行的代码(在两个系统上使用gcc编译): 如果输入为339886769243483 Linux中的输出: lnum => 339886769243**483**.00000000000000000

我有一个项目,我必须用双变量进行一些数学计算。 问题是我在SUN Solaris 9和Linux上得到的结果不同。 有很多方法(在这里和其他论坛中解释)可以让Linux像Sun一样工作,但不是相反。 我不能触摸Linux代码,所以只有SUN可以更改。 有没有办法让SUN像Linux一样运行

我运行的代码(在两个系统上使用gcc编译):

如果输入为339886769243483

Linux中的输出:

lnum  => 339886769243**483**.00000000000000000000

lnum  => 33988676.9243**4829473495483398**

product => 20819503.600158**59827399253845**
在阳光下:

lnum => 339886769243483.00000000000000000000

lnum => 33988676.92434830218553543091

product = 20819503.600158**60199928283691**
注意:结果并不总是不同的,而且大多数时候是相同的。60000个数字中只有10个15位数有这个问题

请帮忙

有两件事:

  • 您需要阅读以下内容:

  • 您需要确定应用程序中对数值精度的要求


这些值相差不到252分之一。但是一个双精度数字只有52位在小数点后面。因此,它们之间的差异只是最后一点。可能是一台机器并不总是正确舍入,但你在做两次乘法,所以答案无论如何都会有那么多错误。

这里的真正答案是另一个问题:你为什么认为你需要这个?可能有一种更好的方法来完成您想要做的事情,它不依赖于复杂的平台浮点细节。话虽如此

不幸的是,您无法更改Linux代码,因为这里的缺陷实际上是Linux结果。太阳的结果尽可能好:它们是正确的圆形;每次乘法得到唯一的(在本例中)最接近结果的C double。相比之下,第一次Linux乘法不能给出正确的四舍五入结果

您的Linux结果来自x86硬件上的32位系统,对吗?您显示的结果与“双舍入”现象一致,并且可能是由“双舍入”现象引起的:第一次乘法的结果首先舍入到64位精度(英特尔x87 FPU内部使用的精度),然后重新舍入到通常的53位双精度。大多数情况下(大约平均2000次中的1999次左右),这种双循环与单循环对53位精度的影响相同,但偶尔会产生不同的结果,这就是您在这里看到的结果

正如您所说,有一些方法可以修复Linux结果以匹配Solaris结果:其中一种方法是使用适当的编译器标志强制使用SSE2指令进行浮点操作(如果可能)。gcc的最新4.5版本还通过一个新标志修复了这一差异,尽管该修复在不使用SSE2时可能会影响性能

[编辑:在几次重读gcc手册之后,gcc修补了邮件列表线程,以及相关的,我仍然不清楚使用
-fexcess precision=standard
是否确实消除了x87系统上的双舍入;我认为答案取决于FLT_EVAL_方法的值。我没有32位Linux/x86机器便于测试。]

但我不知道如何修复Solaris结果以与Linux结果匹配,我也不确定您为什么要这样做:您将使Solaris结果更不准确,而不是使Linux结果更准确

[编辑:caf在这里有一个很好的建议。在Solaris上,尝试故意使用long double作为中间结果,然后强制返回到double。如果操作正确,这将重现您在Linux中看到的双舍入效果。]


请参阅David Monniaux的优秀论文,了解双舍入的良好解释。这是在前面的回答中提到的Goldberg文章之后的重要阅读。

您应该将
lnum
初始化为0-因为您很幸运,结果不完全是垃圾。我大胆猜测,您在32位Lin上也会得到不同的结果ux和64位Linux。这是真的吗?如果是的话,这对你有关系吗?OP可以尝试在SPARC上用
长双精度
进行计算,然后将结果四舍五入为
双精度
——模拟扩展精度x87计算的效果。但这不能保证有效。@caf:好的一点——绝对值得一试但是,在其他一些平台上,它会再次给出不同的结果——例如,OS X/PPC,其中“long double”是一种特殊的“double double”格式,或者Windows,其中“long double”似乎与“double”相同。也许这与OP的需要无关。我想这里的真正答案是另一个问题:“你为什么需要这个?”@Mark Dickinson:谢谢你的详细解释。我明白我想让SUN“错误地”工作。关于原因:我有一个系统使用上述代码(在Linux上)多年来。现在我在SUN上编写了另一个应用程序,它将使用相同的代码并提供相同的输入以产生相同的结果。只要我在SUN和Linux上有相同的值,计算的实际“正确性”就不重要了。@caf:谢谢,我试过了,它在部分情况下有所帮助,但不是所有情况下都有帮助。在第一个例子中不过,计算方面,
lnum=lnum*10.0E-8
帮助更大。我稍后会尝试更多的组合。也许有一些编译器标志可以帮助您?@Marina:很可能x87版本没有将中间结果四舍五入到
双精度
(您必须检查程序集才能确定),因此,请尝试在
长双精度
中进行所有计算,直到最后一步才进行取整。不过,为了获得完美的复制,您可能必须以某种方式将中间结果取整为80位尾数(SPARC的
长双精度
有112位尾数)。
lnum => 339886769243483.00000000000000000000

lnum => 33988676.92434830218553543091

product = 20819503.600158**60199928283691**