#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
float sum=0.0;
for(int i=1;i<=1000000;i++)
sum+=(1.0)/i;
printf("Forward sum is %f ",sum);
sum=0.0;
for(int i=1000000;i>=1;i--)
sum+=(1.0)/i;
printf("Backward sum is %f ",sum);
return 0;
}
输出:- 远期总和是:-14.357358 后退金额为:-14.392652。
为什么两个总和不同?我认为存在一些精度误差,这会导致两个和的差值,但是我无法清楚了解为什么会这样。
答案 0 :(得分:1)
第一个循环开始于将总和增加相对较大的部分,并在总和变大时减小较小的部分。因此,虽然需要更多的位来表示总和,但较少的位可用于较小的部分。
在第二个循环中,将小部分添加到总和中,并在总和变大时添加越来越大的部分。因此,相对于sum的当前值,存储新添加的部分所需的位数更少。
(不是很科学的解释,但是我希望这种口头尝试可以使原理更清楚)
注意:这也意味着第二个结果更加准确。
为了更精确:尝试添加两个浮点数,需要对其进行缩放,以使尾数和指数的位数相同。当总和变大时,添加到的项目将按比例缩放,以免失去该总和的重要性。结果,要相加的部分的最低有效位将在相加之前从寄存器中按比例缩小。例如,(假设)将0.00000001加到1,000,000,000将导致对该大数加零。
答案 1 :(得分:1)
这是浮点算术令人惊讶的方面之一:实际上,您执行加法运算的顺序非常重要。(通常,我们说浮点加法不是可交换的。)
通过一个简单的,稍微虚假的示例,很容易看出为什么会这样。假设您有这个附加问题:
1000000. + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1
但是,假设您使用的单精度浮点格式只有7位精度。因此,即使您可能认为1000000.0 + 0.1
将是1000000.1
,实际上也会四舍五入为1000000.
。因此,1000000.0 + 0.1 + 0.1
也将是1000000.
,并且添加所有0.1
的10个副本也将仅产生1000000.
。
但是,如果您尝试这样做:
0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 1000000.
现在,当您添加0.1 + 0.1
时,精度没有问题,因此得到0.2
。因此,您将0.1
加十倍,得到1.0
。因此,如果按此顺序解决整个问题,您将得到1000001.
。
您可以自己看到。试试这个程序:
#include <stdio.h>
int main()
{
float f1 = 100000.0, f2 = 0.0;
int i;
for(i = 0; i < 10; i++) {
f1 += 0.1;
f2 += 0.1;
}
f2 += 100000.0;
printf("%.1f %.1f\n", f1, f2);
}
在我的计算机上,这将按预期打印100001.0 100001.0
。但是,如果我将两个大数字更改为10000000.0
,则它将打印10000000.0 10000001.0
。这两个数字显然不相等。