如何计算+, - ,*和/?中的舍入误差后的浮点精度?

时间:2013-10-06 15:08:50

标签: c++ floating-point verification floating-point-precision

为了验证的目的,我希望能够在一些特定的算术计算过程中计算由于四舍五入到可表示的值而导致的累积误差的合理上限。

假设我们有一个声称执行某些特定算术运算的函数foo()。还假设对所涉及的类型为floatdouble以及隐含(或陈述)foo()的方式的最大错误(由于四舍五入)存在隐含保证。讽刺计算。

我希望能够通过以跟踪累积的最坏情况错误的方式执行计算来验证foo()对特定输入值集的结果,然后检查是否两个结果与最终的最坏情况错误要求一样接近。

我想通过引入一个新的算术类track_prec<T>来实现这一点,该算术类将精确跟踪添加到一个基本的浮点类型,然后让它由算术的实现来实现该类的运算符计算每个子表达式的最坏情况错误。我的问题是,在这些一般情况下,我不知道如何计算这些最坏情况的错误:

// T = float or double
template<class T> class track_prec {
public:
    T value;
    T ulp; // http://en.wikipedia.org/wiki/Unit_in_the_last_place

    track_prec& operator+=(const track_prec& v)
    {
        value += v.value;
        ulp = ???; // How to do this? And what about -=, *=, and /=?
    }

    friend bool operator==(T, const track_prec&)
    {
        // Exactly how should this comparison be done?
    }
};

例如,假设foo()是对一系列数字的简单求和。然后我们可以使用track_prec<T>,如下所示:

std::vector<T> values { 0.4, -1.78, 1.3E4, -9.29E3, ... };
CHECK_EQUAL(std::accumulate(values.begin(), values.end(), track_prec<T>()),
            foo(values.begin(), values.end()));

当然,欢迎任何类型的帮助,但指向免费和可用代码的指针将非常好。

我在这个主题上找到了这些链接,但它们似乎没有直接回答我的问题。

2 个答案:

答案 0 :(得分:3)

跟踪浮点计算精度的最简单方法是interval arithmetic。它不需要IEEE 754算术,只需要将计算切换到向上或向下舍入,这样每个步骤的计算间隔的范围包含可能由相同的计算产生的所有实数,如果它们是用真实的算术。

您应该能够找到许多现有的区间运算实现。

任何给定步骤的计算精度是在该步骤计算的区间宽度。

注意常数:如果希望近似πx,则需要将包含π的浮点间隔乘以x的间隔。如果将x的区间乘以表示为3.1415926535897932的double,则会得到x乘以该double的误差(既不等于π也不等于3.1415926535897932)。在您的问题的代码中,常量0.4表示“最接近0.4的双精度”。如果需要有理数4/10,请使用其边界为3.9999999999999997e-014.0000000000000002e-01分别表示的两个双精度的区间。

答案 1 :(得分:2)

查看此处如何实施错误跟踪。 https://github.com/Esri/geometry-api-java/blob/master/src/main/java/com/esri/core/geometry/ECoordinate.java

基本思想是浮点运算结果将接近正确的值+ - 0.5 * DBL_EPSILON *值。所以你可以跟踪和积累它。 上述链接中的代码将a + b的绝对误差计算为

err(a+b) = err(a) + err(b) + DBL_EPSILON * abs(a + b). 

假设:IEEE 754双浮点运算使用保护位。