浮点数数组的总和返回不同的结果

时间:2018-11-30 22:27:37

标签: c arrays floating-point

在这里,我有一个类型为sum()的函数float,该函数带有类型为t的指针float和一个整数size。它返回数组中所有元素的总和。然后,我使用该函数创建两个数组。一个在第一个索引处具有BIG值,而在最后一个索引处具有BIG值。当我返回每个数组的总和时,会得到不同的结果。
这是我的代码:

#include <stdlib.h>
#include <stdio.h>

#define N     1024
#define SMALL 1.0
#define BIG   100000000.0

float sum(float* t, int size) {        // here I define the function sum()
  float s = 0.0;
  for (int i = 0; i < size; i++) {
    s += t[i];
  }
  return s;
}

int main() {
  float tab[N];
  for (int i = 0; i < N; i++) {
    tab[i] = SMALL;
  }

  tab[0] = BIG;
  float sum1 = sum(tab, N);            // initialize sum1 with the big value at index 0
  printf("sum1 = %f\n", sum1);

  tab[0] = SMALL;
  tab[N-1] = BIG;
  float sum2 = sum(tab, N);            // initialize sum2 with the big value at last index
  printf("sum2 = %f\n", sum2);

  return 0;
}

编译代码并运行之后,我得到以下输出:

Sum = 100000000.000000
Sum = 100001024.000000

为什么,即使数组具有相同的元素(但索引不同),我也得到不同的结果。

2 个答案:

答案 0 :(得分:2)

  

即使数组具有相同的元素,为什么也得到不同的结果

在浮点数学中,100000000.0 + 1.0等于100000000.0而不是100000001.0,但是100000000.0 + 1024.0等于100001024.0。给定值100000000.0,值1.0太小而无法显示在用于表示100000000.0的可用位中。

因此,当您首先放置100000000.0时,所有以后的+ 1.0操作都无效。

不过,当您将100000000.0放在 last 后面时,之前的1000多个1.0 + 1.0 + ...的确加起来就是1024.0,而1024.0是“足够大”以考虑到浮点数学的可用精度。

答案 1 :(得分:2)

您遇到的是floating point imprecision。这是一个简单的演示。

> which(is.na(combi$Alley))

您期望100000001.0和100000019.0。

int main() {
    float big = 100000000.0;
    float small = 1.0;

    printf("%f\n", big + small);

    printf("%f\n", big + (19 *small));

    return 0;
}

为什么会这样?由于计算机不像我们那样存储数字,因此floating point numbers doubly so$ ./test 100000000.000000 100000016.000000 的大小仅为32位,但是最多可以存储3 ^ 38个数字,而不是32位整数可以存储的仅2 ^ 31个数字。它可以存储小数位。怎么样?他们作弊。它真正存储的是符号,指数和尾数。

float

尾数决定精度,sign * 2^exponent * mantissa 中只有24位。因此,大量数字会失去精度。

您可以read about exactly howplay around with the representation

要解决此问题,请使用精度更高的float,或使用精确但较慢的arbitrary precision library,例如GMP。