在Eigen3中,norm()方法没有提供准确的答案,为什么

时间:2017-02-27 18:14:31

标签: eigen3 norm

我有一种情况,使用Eigen3库,norm()不能提供正确的答案。 norm()应该只是矢量到广场的系数的平方根:

NORM= sqrt( v[1]*v[1] + v[2]*v[2] + .... + v[N]*v[N])

然而,以下函数以两种方式计算norm():使用Eigen3的norm()方法和手动。结果略有不同:

void mytest()
{
    double  mvec[3];
    mvec[0] = -3226.9276456286984;
    mvec[1] = 6153.3425006471571;
    mvec[2] = 2548.5894934614853;

    Vector3d v;
    v(0) = mvec[0];
    v(1) = mvec[1];
    v(2) = mvec[2];
    double normEigen = v.norm();
    double normByHand = sqrt( v(0)*v(0) + v(1)*v(1) + v(2)*v(2));
    double mdiff = abs((normEigen - normByHand));

    std::cout.precision(17);
    std::cout << "normEigen= " << normEigen << std::endl;
    std::cout << "normByHand= " << normByHand << std::endl;
    std::cout << "mdiff= " << mdiff << std::endl;
}

此功能的输出为:

normEigen=  7400.8103858007089
normByHand= 7400.8103858007107
mdiff=      1.8189894035e-12

从数字15开始他们是不同的,为什么?在哪里四舍五入?

提前致谢 PedroC。

2 个答案:

答案 0 :(得分:1)

计算是使用浮点计算的计算。因此,操作的顺序以及诸如矢量化之类的事物可能导致(通常)稍微不同的结果(由于不同的舍入,不同的数量级等)。 在这种情况下,差异仅在第15位。 64位浮点数的最大精度大约是第16位。

如果我们使用boost来查看ULP中的距离:

#include <boost/math/special_functions/next.hpp>
#include <iostream>
int main()
{
    double normEigen = 7400.8103858007089;
    double normByHand = 7400.8103858007107;

    std::cout << boost::math::float_distance(normEigen, normByHand);
    return 0;
}

我们看到距离(至少在我的系统上)是2.所以二进制数是例如 0101 ... 011而不是0101 ... 001。如此小的差异几乎总是由于我上面列出的原因。

答案 1 :(得分:0)

更深入我看到,当我在一个唯一向量中计算squaredNorm时,平方值的总和会引入差异 仅使用一个tem的3个向量我看到总数不相同。

void mytest2()
{
    double  mvec[3];
    mvec[0] = -3226.9276456286984;
    mvec[1] = 6153.3425006471571;
    mvec[2] = 2548.5894934614853;

    Vector3d v, v1, v2, v3;
    v(0) = mvec[0];
    v(1) = mvec[1];
    v(2) = mvec[2];
    v1(0) = mvec[0]; v1(1) = v1(2) = 0.0;
    v2(0) = 0.0; v2(1) = mvec[1]; v2(2) = 0.0;
    v3(0) = v3(1) = 0.0; v3(2) = mvec[2];

    double squnorm = v.squaredNorm();
    double squnorm1 = v1.squaredNorm();
    double squnorm2 = v2.squaredNorm();
    double squnorm3 = v3.squaredNorm();
    double squnormbyhand = squnorm1 + squnorm2 + squnorm3;
    double sqdiff = abs(squnorm - squnormbyhand);

    std::cout.precision(17);
    std::cout << "normEigen= " << squnorm << std::endl;
    std::cout << "normByHand= " << squnormbyhand << std::endl;
    std::cout << "mdiff= " << sqdiff << std::endl;
}

此功能的输出是:

normEigen=  54771994.366575643
normByHand= 54771994.366575658
mdiff=     1.49011161193847656e-8

由于某些原因,当添加平方值时,Eigen会引入舍入差异。

无论如何,谢谢你的回答。

佩德罗