我想计算Rosenbrock的测试函数
我已经实现了以下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
。
我非常确定,我看到的这种效果应该归因于浮点运算的精度。有人可以确认这一点,并向我解释发生这种情况的机制吗?
您可以temp = 3604.0f
在每次迭代中准确地进行计算。当您尝试添加3604.0f
其他内容并将结果四舍五入到最接近值时,就会出现问题float
。float
s存储一个指数和23位有效数字,这意味着相隔24位以上的1位结果将四舍五入为除它以外的其他值。
请注意,3604 = 901 * 4,且901的二进制扩展为1110000101;当您开始添加temp
大于2 ^ 24 * 4 = 67108864的内容时,您将开始看到四舍五入。(这也发生在您运行代码时;当sum_host超过67108864时,它会开始打印出3600,因为连续sum_host的右边之间存在差异。 )当您添加temp
大于2 ^ 26 * 4的东西时,您开始看到甚至更多的舍入;那时,第二个最小的“ 1”位也被吞咽了。
请注意,在进行Kahan求和后,sum_host
您将报告ANDc
为-108
。这很松散,因为c
它一直在跟踪接下来的最高24位。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句