如何提高乘法的精度

How to improve precision in multiplication?

本文关键字:精度 何提高      更新时间:2023-10-16

我使用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-161.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的经典之作《每个计算机科学家都应该知道的浮点运算》