我使用C ++实现超限插值算法(http://en.wikipedia.org/wiki/Transfinite_interpolation)。一切看起来都很好,直到我试图测试一些小数字,结果看起来很奇怪和不正确。我想它必须与精度损失有关。代码是
for (int j = 0; j < Ny+1; ++j)
{
for (int i = 0; i < Nx+1; ++i)
{
int imax = Nx;
int jmax = Ny;
double CA1 = (double)i/imax; // s
double CB1 = (double)j/jmax; // t
double CA2 = 1.0-CA1; // 1-s
double CB2 = 1.0-CB1; // 1-t
point U = BD41[j]*CA2 + BD23[j]*CA1;
point V = BD12[i]*CB2 + BD34[i]*CB1;
point UV =
(BD12[0]*CB2 + BD41[jmax]*CB1)*CA2
+ (BD12[imax]*CB2 + BD23[jmax]*CB1)*CA1;
tfiGrid[k][j][i] = U + V - UV;
}
}
我想当BD12[i]
(或BD34[i]
或BD41[j]
或BD23[j]
)非常小时,舍入错误或某些内容会累积并变得无法忽略。任何想法如何处理这种情况?
PS:尽管有数百万次提出过类似的问题。我仍然无法弄清楚它与我的乘法或除法或减法有什么关系?
答案 0 :(得分:2)
除了Antoine制作的要点(一切都非常好):
它可能值得记住,添加两个值非常
不同的数量级将导致非常大的损失
精确。例如,如果CA1
小于约1E-16
,
1.0 - CA1
可能仍为1.0
,即使只是CA1
稍大一点,你会松散几位数的精度。
如果这是问题所在,您应该能够将其隔离
在内循环中放入一些打印语句,并查看
您要添加的值(或者甚至可能使用调试器)。
该怎么做才是另一个问题。可能有一些
您正在尝试做的数值稳定的算法;
我不知道。否则,您可能必须检测到
动态问题,并重写方程,以避免它,如果它
发生。 (例如,要检测1.0 / CA1
是否太小
此外,您可以检查{{1}}是否超过
几千,或者几百万,或者你精确度多少
可以负担得起。)
答案 1 :(得分:1)
使用C / C ++构建的算术的准确性是有限的。当然,错误会在您的情况下累积。
您是否考虑过使用提供更高精度的库?也许看看https://gmplib.org/
一个简短的例子,清除了更高的准确性:
double d, e, f;
d = 1000000000000000000000000.0;
e = d + 1.0;
f = e - d;
printf( "the difference of %f and %f is %f\n", e, d, f);
这不会打印1而是0.对于gmplib,代码看起来像:
#include "gmp.h"
mpz_t m, n, r;
mpz_init( m);
mpz_init( n);
mpz_init( r);
mpz_set_str( m, "1 000 000 000 000 000 000 000 000", 10);
mpz_add_ui( n, m, 1);
mpz_sub( r, n, m);
printf( "the difference of %s and %s is %s (using gmp)\n",
mpz_get_str( NULL, 10, n),
mpz_get_str( NULL, 10, m),
mpz_get_str( NULL, 10, r));
mpz_clear( m);
mpz_clear( n);
mpz_clear( r);
这将返回1.
答案 2 :(得分:1)
您的算法似乎没有通过在每次迭代时重复使用先前的计算来累积错误,因此在不查看数据的情况下很难回答您的问题。
基本上,您有3个选项:
提高数字的精确度:x86 CPU可以处理float
(32位),double
(64位)和long double
(80位)。除此之外,你必须使用&#34; soft&#34;浮点,所有操作都是用软件而不是硬件实现的。有一个很好的C lib就是这样做的:MPFR基于GMP,GNU建议使用MPFR。我强烈建议使用更容易使用的C ++包装器,如boost multiprocesion。预计您的计算速度会慢一些。
通过在计算中使用比单个标量数字更丰富的信息来分析精度损失的来源。根据MPFR查看interval arithmetic和MPFI lib。 CADENA是另一种非常有前途的解决方案,基于随机更改硬件的舍入模式,并且运行时成本低。
执行静态分析,它甚至不需要运行代码并通过分析算法来工作。不幸的是,我没有使用过这些工具的经验,所以我不能推荐除了护目镜以外的任何东西。
我认为最好的方法是在开发算法时运行静态或动态分析,识别精度问题,通过更改算法或使用更高精度来解决最不稳定的变量 - 而不是其他人避免过多的性能在运行时的影响。
答案 3 :(得分:1)
数值(即浮点)计算是 hard 精确地做。你必须特别改变各种变量,主要是你失去精确度。在这种情况下,1.0 - CA1
等可疑(如果CA1
非常小,您将获得1)。重新组织你的表达,维基百科文章(存根!)可能是为了理解(显示对称性,...)和aestetics而不是数字稳健性而编写的。
搜索关于数值计算的课程/讲义,你应该包括一个介绍性的章节。查看Goldberg的经典What every computer scientist should know about floating point arithmetic。