随机排序的IEEE 754双精度浮点数之和的结果

时间:2017-11-14 22:37:49

标签: floating-point precision ieee-754

这是我的问题的伪代码。

我有一组 IEEE 754 双精度正数。

数组可以按随机顺序排列,但数字总是相同的,只是在它们的位置上乱码。此类数字double表示的有效IEEE范围内可以在很宽的范围内变化

获得列表后,我会初始化一个变量:

double sum_result = 0.0;

我在sum_result上累积总和,在整个数组的循环中。在每一步我都做:

sum_result += my_double_array[i]

是否保证,无论double的初始数组的顺序如何,如果数字相同,打印出的总和结果将始终相同?

3 个答案:

答案 0 :(得分:2)

没有

举一个简单的例子,将1加到0x1p53会产生0x1p53。 (这使用十六进制浮点表示法。“p”之前的部分是有效数字,以十六进制表示,与C十六进制整数常量相同,除了它可能有一个“。”标记分数的开头“p”后面的数字表示有效数乘以2的幂。)这是因为数学上精确的和,0x1.00000000000008p + 53,不能用IEEE-754 64位二进制浮点表示,因此它的四舍五入到最接近的值,其有效位数为偶数位,即0x1p53。

因此,0x1p53 + 1产生0x1p53。所以0x1p53 + 1 + 1,从左到右计算,也产生0x1p53。但是,1 + 1是2,并且2 + 0x1p53可以准确表示,因为0x1.0000000000001p + 53,所以1 + 1 + 0x1p53是0x1.0000000000001p + 53。

为了以十进制显示更容易可视化的示例,假设我们只有两位小数。然后100 + 1产生100,所以100 + 1 + 1 + 1 + 1 + 1 + 1产生100.但是1 + 1 + 1 + 1 + 1 + 1 + 100累积到6 + 100然后产生110(由于四舍五入到两位有效数字)。

答案 1 :(得分:1)

  

是否保证,无论初始数组double的顺序如何,如果数字相同,打印出的总和结果将始终相同?

不,FP添加不是associative。记住它被称为浮动点 - 绝对精度"浮动"约相对于1.0。任何给定的operation添加内容(+)都受round-off error的约束。

然而,如果总和完成并且不精确标志是明确的,那么是,订单不相关。**

简单的反例。

#include <math.h>
#include <float.h>
#include <fenv.h>
#include <stdio.h>

int main(void) {
  double a[3] = { DBL_MAX, -DBL_MAX, 1.0 };
  fexcept_t flag;

  feclearexcept(FE_ALL_EXCEPT);
  printf("%e\n", (a[0] + a[1]) + a[2]);
  fegetexceptflag(&flag, FE_INEXACT);
  printf("Inexact %d\n", !!(flag & FE_INEXACT));

  feclearexcept(FE_ALL_EXCEPT);
  printf("%e\n", a[0] + (a[1] + a[2]));
  fegetexceptflag(&flag, FE_INEXACT);
  printf("Inexact %d\n", !!(flag & FE_INEXACT));

  printf("%d\n", FLT_EVAL_METHOD);
  return (EXIT_SUCCESS);
}

输出

1.000000e+00  // Sum is exact
Inexact 0

0.000000e+00  // Sum is inexact
Inexact 1

0    // evaluate all operations ... just to the range and precision of the type;

根据FLT_EVAL_METHOD,FP数学可能会使用更宽的进动和范围,但上面的极端示例总和仍然会有所不同。

**除了可能是0.0 vs -0.0

的结果

要了解原因,请尝试使用4位精度的基于10的文本示例。同样的原则适用于double及其通常的53位精确二进制数字。

a[3] = +1.000e99, -1.000e99, 1.000
sum = a[0] + a[1]   // sum now exactly 0.0 
sum += a[2]         // sum now exactly 1.0 
// vs.
sum = a[1] + a[2]   // sum now inexactly -1.000e99
sum += a[0]         // sum now inexactly 0.0

Re:&#34;打印出的总和结果将始终相同&#34; :除非代码打印的"%a""%.*e"具有更高的精度,否则打印的文本可能缺乏显着性,而两个不同的总和可能看起来相同。见Printf width specifier to maintain precision of floating-point value

答案 2 :(得分:1)

让我们举一个例子:我使用基数为10的模型转换浮点问题,只有2位有效数字,操作结果四舍五入到最近。

假设我们必须总结3个数字9.9 + 8.4 + 1.4
确切的结果是19.7,但我们只有两位数,所以它应该舍入为20.

如果我们先对9.9 + 8.4求和,我们会得到18.3,然后四舍五入为18.
然后我们总结18. + 1.4我们将19.4四舍五入为19.

如果我们首先对最后两个词8.4 + 1.4求和,我们得到9.8,则不需要舍入。
然后9.9 + 9.8我们将19.7四舍五入为20.,结果不同。

(9.9 + 8.4) + 1.49.9 + (8.4 + 1.4)不同,sum运算不是关联的,这是由于中间舍入。我们也可以用其他舍入模式展示类似的例子......

问题在基数2中与53位有效数字完全相同:无论基数或有效长度如何,中间舍入都将导致非关联性。

要消除这个问题,您可以对数字进行排序,使顺序总是相同,或者消除中间舍入并仅保留最后一个,例如使用超级累加器,例如https://arxiv.org/pdf/1505.05571.pdf
...或者只是接受一个近似的结果(由您来分析平均或更差的错误并决定是否可以接受......)。