c ++浮点减法误差和绝对值

jor*_*gen 3 c++ floating-point rounding-error floating-accuracy subtraction

我理解它的方式是:当double在c ++中用双精度减去两个数时,它们首先被转换为有效数,从指数的2次开始.如果减去的数字在有效数字中具有相同的指数和许多相同的数字,则会出现错误,从而导致精度损失.为了测试我的代码,我编写了以下安全添加功能:

double Sadd(double d1, double d2, int& report, double prec) {
    int exp1, exp2;
    double man1=frexp(d1, &exp1), man2=frexp(d2, &exp2);
    if(d1*d2<0) {
        if(exp1==exp2) {
            if(abs(man1+man2)<prec) {
                cout << "Floating point error" << endl;
                report=0;
            }
        }
    }
    return d1+d2;
}
Run Code Online (Sandbox Code Playgroud)

然而,测试这个我注意到一些奇怪的事情:似乎实际错误(不是函数报告错误而是计算产生的实际错误)似乎取决于减去数字的绝对值而不仅仅是相等数字的数字在有意义的...

例如,使用1e-11精度prec并减去以下数字:

1)9.8989898989898-9.8989898989897:该函数报告错误,我得到高度不正确的值9.9475983006414e-14

2)98989898989898-98989898989897:该函数报告错误但我得到正确的值1

显然我误解了一些事情.有任何想法吗?

Pet*_*ker 6

如果减去两个几乎相等的浮点值,结果将主要反映低位的噪声.这里几乎相等的不仅仅是相同的指数和几乎相同的数字.例如,1.0001和1.0000几乎相等,减去它们可以通过这样的测试捕获.但1.0000和0.9999的数量完全相同,并且不会被这样的测试所捕获.

此外,这不是安全的添加功能.相反,它是对设计/编码错误的事后检查.如果你减去两个非常接近的值,那么噪音很重要你就犯了一个错误.修复错误.我并不反对使用这样的东西作为调试辅助工具,但是请把它称之为暗示它就是这样的东西,而不是暗示浮点加法本身就存在危险.此外,将检查放在添加函数内似乎是过分的:断言这两个值不会导致问题,然后是一个普通的旧浮点加法,可能会更好.毕竟,代码中的大多数添加都不会导致问题,您最好知道问题所在的位置; 把断言置于问题点.

  • 如果你写“如果你减去两个几乎相等的**近似**浮点值,结果将主要反映低位中的噪声”,那么没有人会狡辩。根据您的编写方式,有人可能会指出两个几乎相等的浮点值相减是一个精确运算(Sterbenz 引理)。 (2认同)
  • @jorgen:此外,前面的内容清楚地表明此问题与浮点无关.这是纯粹的数学.如果你有两个值,d1和d2可能有任何类型的错误(计算错误,测量误差,样本错误),你计算r = d1 + d2,r的数量远小于d1或d2,那么r中的相对误差远大于d1或d2中的相对误差.例如,如果d1为100,误差为1%,d2为-100且误差为1%,则r为-2到2之间的任何值,可能存在无限的相对误差.没有涉及浮点数. (2认同)