如果遵循IEEE 754的两种语言,则两种语言的计算都会产生相同的答案

If two languages follow IEEE 754, will calculations in both languages result in the same answers?

本文关键字:两种 语言 答案 IEEE 如果 计算      更新时间:2023-10-16

我正在将程序从SCILAB代码转换为C 。尤其是一个循环是与原始Scilab代码产生的结果略有不同(这是一条很长的代码,所以我不会将其包括在问题中,但我会尽力总结以下问题)。

问题是,循环的每个步骤都使用上一步中的计算。此外,计算之间的差异仅在第100,000次迭代左右(大约300,000)。

注意:我将C 程序的输出与使用"格式(25)"的Scilab 5.5.2的输出进行比较。命令。这意味着我要比较25个重要数字。我还想指出,我了解在一定数量的位之后无法保证精确度,但是在评论之前请阅读以下部分。到目前为止,所有计算在两种语言之间最多25位数字。

试图解决这个问题的底部,到目前为止,我已经尝试过:

  1. 检查所使用的数据类型:

我设法确认Scilab正在使用IEEE 754双打(根据语言文档)。另外,根据Wikipedia的说法,C 并不需要使用IEEE 754进行双打,但是据我所知,我在C 中使用double的任何地方都可以与Scilab的结果匹配。

  1. 检查先验功能的使用:

我还从每个计算机科学家都知道的有关浮点算术的知识中读到,IEEE不需要精确的函数才能完全舍入。考虑到这一点,我已经比较了这些功能的结果(sin(),cos(),exp()),同样,结果似乎是相同的(最多25位数字)。

  1. 使用其他功能和预定义值:

我重复了使用SQRT()和POW()的上述步骤。以及PI的值(我在C 中使用M_PI和SCILAB中的%PI)。同样,结果相同。

  1. 最后,我已经重写了循环(非常仔细),以确保两种语言之间的代码相同。

注意:有趣的是,我注意到,对于上述所有计算,两种语言之间的结果比计算的实际结果(在浮点算术之外)匹配。例如:

使用wolfram alpha = 0.123456789 ....

使用scilab& sin(x)的价值C = 0.12345yyyyy .....

即使一旦使用Scilab或C 计算的值也开始与实际结果(来自Wolfram)不同。每种语言的结果仍然相互匹配。这使我相信,大多数值以相同的方式计算(两种语言之间)。即使IEEE 754不需要它们。


我的原始思维是上面的前三点之一,两种语言之间的实现方式不同。但是从我可以说的一切似乎都产生了相同的结果。

即使这些循环的所有输入都是相同的,结果也可能有所不同吗?可能是因为一个非常小的错误(过去我可以看到25位数字)正在发生随着时间的推移积累吗?如果是这样,我该如何解决此问题?

no,编号系统的格式不能保证功能的等效答案用不同的语言。

函数(例如sin(x))可以使用相同的语言(以及不同的语言)以不同的方式实现。sin(x)功能是一个很好的例子。许多实现将使用带有插值的查找表或查找表。这具有速度优势。但是,某些实现可能会使用泰勒系列来评估该功能。某些实现可能会使用多项式来提出近似值。

具有相同的数字格式是在语言之间解决的一个障碍。功能实现是另一个。

记住,您也需要考虑该平台。使用80位浮点处理器的程序将具有与使用64位浮点软件实现的程序不同的结果。

一些架构提供了使用扩展精度浮点寄存器的功能(例如,内部80个位,与RAM中的64位值相比)。因此,根据计算的结构方式以及用于编译代码的优化级别,可以对相同的计算获得略有不同的结果。

是的,可能会有不同的结果。即使您在同一平台中使用同一编程语言中完全相同的源代码,也可能。有时足以拥有不同的编译器开关;例如,-ffastmath将导致编译器以速度而不是准确性来优化您的代码,并且,如果您的计算问题一开始没有很好地条件,则结果可能是显着不同的。 。

例如,假设您有此代码:

 x_8th = x*x*x*x*x*x*x*x;

计算此方法的一种方法是执行7个乘法。这将是大多数编译器的默认行为。但是,您可能需要通过指定编译器选项-ffastmath来加快此功能,并且结果代码只有3个乘法:

temp1 = x*x; temp2 = temp1*temp1; x_8th = temp2*temp2;

结果将略有不同,因为有限的精度算术不是关联的,但对于大多数应用程序而言,足够接近。但是,如果您的计算没有充分的条件,那么小错误会很快被放大到一个大错误中。

请注意,Scilab和C 不是使用完全相同的指令序列,或者一个使用FPU,另一个使用SSE,因此可能没有一种方法使它们完全相同。

i Inspectable所评论,如果您的编译器具有_control87()或类似的内容,则可以使用它来更改精度和/或舍入设置。您可以尝试对此进行组合以查看它是否有任何效果,但是再次,即使您设法获得Scilab和C 相同的设置,实际说明序列的差异也可能是问题。

http://msdn.microsoft.com/en-us/library/e9b52ceh.aspx

如果使用了SSE,我不确定可以调整什么,因为我认为SSE没有80位精度模式。

在32位模式下使用FPU的情况下,如果您的编译器没有_control87之类的内容,则可以使用汇编代码。如果不允许内联装配,则需要调用汇编功能。此示例来自一个旧的测试程序:

static short fcw; /* 16 bit floating point control word */
/* ... */
/* set precision control to extended precision */
__asm{
    fnstcw fcw
    or fcw,0300h
    fldcw fcw
}