Rosenbrock测试函数计算的准确性

时间:2015-01-07 22:25:00

标签: c++ c floating-point floating-accuracy

我想计算Rosenbrock的测试函数

enter image description here

我已经实现了以下C / C ++代码

#include <stdio.h>

/********/
/* MAIN */
/********/
int main()
{
    const int N = 900000;

    float *x = (float *)malloc(N * sizeof(float));
    for (int i=0; i<N; i++) x[i] = 3.f;

    float sum_host = 0.f;
    for (int i=0; i<N-1; i++) {
        float temp = (100.f * (x[i+1] - x[i] * x[i]) * (x[i+1] - x[i] * x[i]) + (x[i] - 1.f) * (x[i] - 1.f));
        sum_host = sum_host + temp;
        printf("%i %f %f\n", i, temp, sum_host);
    }
    printf("Result for Rosenbrock's test function calculation = %f\n", sum_host);

}

由于x数组已初始化为3.f,因此每个求和项应为3604.f,因此涉及899999项的最终求和应为3243596396 }。但是,我得到的结果是3229239296,绝对误差为14357100。如果我衡量两个连续的部分求和之间的差异,我发现早期部分求和是3600.f,然后最后一个得到3584,而它应该始终是3604.f }。

如果我使用Kahan求和算法

sum_host = 0.f;
float c        = 0.f;
for (int i=0; i<N-1; i++) {
    float temp = (100.f * (x[i+1] - x[i] * x[i]) * (x[i+1] - x[i] * x[i]) + (x[i] - 1.f) * (x[i] - 1.f)) - c;
    float t    = sum_host + temp;
    c          = (t - sum_host) - temp;
    sum_host = t;
}

我得到的结果是3243596288,绝对误差小得多108

我很确定我看到的效果应该归结为浮点算术的精确度。有人可以证实这一点,并向我提供一个解释机制,根据这种机制发生这种情况?

2 个答案:

答案 0 :(得分:4)

您在每次迭代时准确计算temp = 3604.0f。当您尝试将3604.0f添加到其他内容并将结果四舍五入到最近的float时,会出现问题。 float存储一个指数和一个23位有效数字,这意味着任何超过24位的1位结果将被四舍五入到不同于它的位置。

注意3604 = 901 * 4,901的二进制扩展为1110000101;一旦你开始将temp添加到大于2 ^ 24 * 4 = 67108864的东西,你就会开始看到舍入。(当你运行代码时也会发生这种情况;它开始打印3600作为连续之间的差异当sum_host超过67108864时sum_host正确。)当你将temp添加到大于2 ^ 26 * 4的东西时,你会开始看到更多的舍入;在那一点上,第二个最小的&#39; 1&#39;有点被吞下去了。

请注意,在您进行Kahan求和后,sum_host就是您报告的内容而c-108。这是松散的,因为c正在跟踪下一个最重要的24位。

答案 1 :(得分:2)

典型的float只有7位数的精度。将3604重复添加到比它大100000倍的数字上,不能很好地累积较低有效数字。

使用double