计算数值误差

Compute numerical error

如本 所示,MKL 给出的结果在串行执行和分布式执行之间存在差异。因此,我想研究那个错误。从我的书中我有:

|ε_(x_c)| = |x - x_c| <= 1/2 * 10^(-d),其中 d 指定准确的小数位数,介于实际数字 x 和计算机的数字之间,x_c.

|ρ_(x_c)| = |x - x_c|/|x| <= 5 * 10^(-s)绝对相对误差,其中s指定有效位数。

所以,我们可以这样写代码:

double calc_error(double a,double x)
{
  return std::abs(x-a)/std::abs(a);
}

为了计算绝对误差,例如

除了绝对误差和绝对相对误差之外,还有更多的误差类型需要研究吗?

以下是我可以使用的一些数据:

serial gives:
-250207683.634793 -1353198687.861288 2816966067.598196 -144344843844.616425 323890119928.788757
distributed gives:
-250207683.634692 -1353198687.861386 2816966067.598891 -144344843844.617096 323890119928.788757

然后我可以将想法扩展到实际数据和结果。

没有比绝对和绝对相对误差更复杂的了。还有另一种比较浮点格式的整数表示的方法,其想法是您希望 "tolerance" 适应您正在比较的数字的大小(特别是因为没有 "as many"可表示的数字取决于震级)。

总而言之,我认为您的问题与浮点数比较非常相似,其中有this excellent guide, and this more exhaustive but much longer paper

为了比较浮点值,可能还值得加入这些:

#include <limits>
#include <cmath>

template <class T>
struct fp_equal_strict
{
    inline bool operator() ( const T& a, const T& b )
    {
        return std::abs(a - b) 
            <= std::max(
                std::numeric_limits<T>::min() * std::min( std::abs(a), std::abs(b) ),
                std::numeric_limits<T>::epsilon()
            );
    }
};

template <class T>
struct fp_equal_loose
{
    inline bool operator() ( const T& a, const T& b )
    {
        return std::abs(a - b) 
            <= std::max(
                std::numeric_limits<T>::min() * std::max( std::abs(a), std::abs(b) ),
                std::numeric_limits<T>::epsilon()
            );
    }
};

template <class T>
struct fp_greater
{
    inline bool operator() ( const T& a, const T& b )
    {
        return (a - b) >= std::numeric_limits<T>::min() * std::max( std::abs(a), std::abs(b) );
    }
};

template <class T>
struct fp_lesser
{
    inline bool operator() ( const T& a, const T& b )
    {
        return (b - a) >= std::numeric_limits<T>::min() * std::max( std::abs(a), std::abs(b) );
    }
};

我要提到的是,还可以执行 ULP(最后位置的单位)比较,它显示二进制表示中两个浮点数的距离。这是 "closeness" 的一个很好的指示,因为如果两个数字例如相隔一个 ULP,则意味着它们之间没有浮点数,因此它们在二进制表示中尽可能接近,而不会实际相等。

此方法的描述 here 比从同一作者接受的答案链接的文章更新的版本。还提供了示例代码。

顺便说一句,但与您的工作上下文相关(比较顺序浮点计算与并行浮点计算)重要的是要注意浮点运算不是关联的,这意味着并行实现通常可能不会给出相同的结果作为顺序实现。即使更改编译器和优化选项实际上也会导致不同的结果(例如 GCC 与 ICC,-O0 与 -O3)。

可以找到有关如何减少执行浮点数求和的错误计算的示例算法 here and a comprehensive document by the author of that algorithm can be found here