在这里,我有一个类型为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
为什么,即使数组具有相同的元素(但索引不同),我也得到不同的结果。
答案 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 how和play around with the representation。
要解决此问题,请使用精度更高的float
,或使用精确但较慢的arbitrary precision library,例如GMP。