四舍五入误差C(向前和向后总和)

时间:2018-08-12 13:46:04

标签: c floating-point precision

#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。

为什么两个总和不同?我认为存在一些精度误差,这会导致两个和的差值,但是我无法清楚了解为什么会这样。

2 个答案:

答案 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。这两个数字显然不相等。