在纯c++中检测精度损失

detect the loss of precision in pure C++

本文关键字:精度 损失 检测 c++ 在纯      更新时间:2023-10-16

当您使用浮点数(float, double, long double类型)操作时,是否可以检测精度损失?说:

template< typename F >
F const sum(F const & a, F const & b)
{
    F const sum_(a + b);
    // The loss of precision must be detected (here or one line above) if some fraction bit is lost due to rounding
    return sum_;
}
x87 FPU存在于目标体系结构上,但没有asm例程对纯c++代码的干预时,

特别感兴趣。 c++ 11gnu++11特定的特性也被接受。

c++标准对浮点精度的概念非常模糊。没有完全符合标准的方法来检测精度损失。

GNU提供了一个扩展来启用浮点异常。您想要捕获的例外是FE_INEXACT

可以帮助您的是std::numeric_limits<double>::epsilon,它返回"1与可表示的大于1的最小值之间的差值"。换句话说,它告诉您x>0的最大值,使得1+x的求值为1。

您可以考虑在boost库中使用间隔算法。它可以保证一个区间的误差在计算过程中总是递增的特性:∀ x ∈[a,b], f(x) ∈ f([a,b]) .

在您的示例中,您可以考虑将初始范围[a-EPS,a+EPS]用于初始数字a。经过一系列操作后,abs(y-x)的结果区间[x,y]将是您想要知道的(最大)精度损失。

您可以使用如下内容:

#include <iostream>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
template <typename F> F sum (const F a, const F b, F &error) {
    int round = fegetround();
    fesetround(FE_TONEAREST);
    F c = a + b;
    fesetround(FE_DOWNWARD);
    F c_lo = a + b;
    fesetround(FE_UPWARD);
    F c_hi = a + b;
    fesetround(FE_TONEAREST);
    error = std::max((c - c_lo), (c_hi - c));
    fesetround(round);
    return c;
}

int main() {
    float a = 23.23528;
    float b = 4.234;
    float e;
    std::cout << sum(a, b, e) << std::endl;
    std::cout << e << std::endl;
}

error参数中返回最大错误量的快速估计。请记住,切换舍入模式会刷新浮点单元(FPU)管道,所以不要期望超高速。

一个更好的解决方案是尝试区间算术(倾向于给出悲观的错误区间,因为变量相关性没有考虑在内),或者仿射算术(跟踪变量相关性,从而给出更严格的错误界限)。

在这里阅读这些方法的入门:http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.36.8089