如何提高乘法的精度
How to improve precision in multiplication?
我使用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:尽管类似的问题已经被问过数百万次了。我还是不知道它和乘法,除法,减法有关吗?
除了Antoine提出的观点(都很好):可能值得记住的是,用very添加两个值不同的数量级会造成非常大的损失精度。例如,如果CA1
小于1E-16
,1.0 - CA1
可能仍然是1.0
,即使它只是再大一点,你就会失去几个数字的精度。如果这就是问题所在,你应该可以通过在内循环中放入一些print语句,并查看您正在添加的值(或者甚至可以使用调试器)。
CA1
是否太小另外,您可以检查1.0 / CA1
是否大于几千个,或者几百万个,不管你有多精确)
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 %fn", e, d, f);
这将打印0而不是1。使用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
你的算法似乎不会通过在每次迭代中重复使用以前的计算来积累错误,所以如果不查看你的数据,很难回答你的问题。
基本上,你有3个选择:
-
提高数字的精度:x86 cpu可以处理
float
(32位),double
(64位)和long double
(80位)。除此之外,您必须使用"软"浮点数,其中所有操作都是在软件而不是硬件中实现的。有一个很好的C库可以做到这一点:基于GMP的MPFR, GNU推荐使用MPFR。我强烈建议使用易于使用的c++包装器,如boost multiprocessing。 -
通过在计算中使用比单个标量数字更有信息量的东西来分析精度损失来自何处。看看区间算法和MPFI库,基于MPFR。CADENA是另一个非常有前途的解决方案,它基于随机改变硬件的舍入模式,并且具有较低的运行时成本。
-
执行静态分析,这甚至不需要运行您的代码,并通过分析您的算法来工作。不幸的是,我没有使用这些工具的经验,所以我不能推荐除了goggle以外的任何工具。
我认为最好的方法是在开发算法时运行静态或动态分析,确定精度问题,通过更改算法或对最不稳定的变量使用更高的精度来解决这些问题,而不是其他方法,以避免在运行时对性能造成太大影响。
数值(即浮点数)计算很难精确地完成。你必须特别注意各种减法,这是你失去精度的地方。在这种情况下,1.0 - CA1
等是可疑的(如果CA1
非常小,您将得到1)。重新组织您的表达式,维基百科文章(存根!)可能是为了理解(显示对称性,…)和美学而编写的,而不是数值稳健性。
查找有关数值计算的课程/课堂讲稿,其中应该包含这方面的介绍性章节。看看Goldberg的经典之作《每个计算机科学家都应该知道的浮点运算》
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 正在将csv文件读取为双精度矢量
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 如何提高计算浮点数的精度?
- 操作顺序以最大限度地提高精度
- 执行时间:与Java BigInteger相比,提高了多精度
- 为什么 cout.precision() 会提高浮点精度?
- 如何提高iOS上的std :: sin功能的精度
- 如何在 c++ 中提高双精度的精度
- 如何提高大量C 的POW精度(10^19)
- 如何提高代码的精度
- 如何以模板类型名称相关的方式提高C++模板的精度
- 使用系列时提高精度
- 如何提高C++除法精度不足的结果精度
- 提高文本文件中字符串向量的精度
- 如何提高轮廓精度
- 增加SIFT中检测到的特征的数量将提高精度
- 如何提高乘法的精度