【问题标题】:Sum of array of floats returns different results [duplicate]浮点数组的总和返回不同的结果[重复]
【发布时间】:2018-11-30 22:27:36
【问题描述】:

这里我有一个float 类型的函数sum(),它接收一个float 类型的指针t 和一个整数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

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

【问题讨论】:

标签: c arrays floating-point


【解决方案1】:

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

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

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

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

    return 0;
}

您会期望 100000001.0 和 100000019.0。

$ ./test
100000000.000000
100000016.000000

为什么会这样?因为计算机不像我们那样存储数字,floating point numbers doubly sofloat 的大小只有 32 位,但可以存储大约 3^38 的数字,而不是 32 位整数只能存储 2^31。它可以存储小数位。如何?他们作弊。它真正存储的是符号、指数和尾数。

sign * 2^exponent * mantissa

尾数决定准确性,float 中只有 24 位。如此大的数字会失去精度。

您可以read about exactly howplay around with the representation

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

【讨论】:

    【解决方案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放在最后时,所有之前的 1000+1.0 + 1.0 + ... 加起来就是1024.0,而1024.0 是“足够大的”,可以产生影响浮点数学的可用精度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-26
      • 2011-04-13
      • 1970-01-01
      • 2016-06-23
      • 2019-10-29
      • 2020-06-13
      • 2020-07-28
      • 1970-01-01
      相关资源
      最近更新 更多