检测纯C ++中的精度损失

时间:2013-01-19 20:47:00

标签: c++ gcc g++

当您使用浮点数(floatdoublelong 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 ++ 11 gnu ++ 11 也会被接受。

4 个答案:

答案 0 :(得分:4)

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

GNU provides an extension启用浮点异常。您想要捕获的异常是FE_INEXACT

答案 1 :(得分:1)

有助于您的一件事是std::numeric_limits<double>::epsilon,它返回“1和最大值之间的差值,大于1可表示”。换句话说,它会告诉您最大的x&gt; 0,以便1+x评估为1。

答案 2 :(得分:1)

您可以考虑在boost库中使用interval arithmetic。它可以保证在计算期间间隔的误差始终增加的属性:∀ x ∈[a,b], f(x) ∈ f([a,b])

在您的情况下,您可以考虑将初始范围[a-EPS,a+EPS]用于初始数字a。经过一系列操作后,结果间隔abs(y-x)的{​​{1}}将是您想知道的(最大)精度损失。

答案 3 :(得分:1)

您可以使用以下内容:

#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