Eigen版本3.2.0和3.3.4之间的数值差异

时间:2018-10-03 16:07:20

标签: c++ precision eigen3

我最近从Eigen 3.2.0到3.3.4推出了使用一些基本向量数学和SelfAdjointEigenSolver的代码。该代码是使用Matlab进行原型设计的,并同意3.2.0。滚动到3.3.4的动机是为了避免在C ++ 11(及更高版本)和3.2.0中发生一些警告和错误。

该代码通过将成千上万的点读入Eigen::Matrix<double, Eigen::Dynamic, 3>来工作。当我使用gdb检查值时,输入值是相同的。下面显示了一段显示数值差异的代码。 pilType被定义为double

// this is the point cloud, center it about the origin
Eigen::Matrix<pilType, 1, 3> center = gridPnts.colwise().mean();
gridPnts.rowwise() -= center;
// Get the transformation matrix to align the point cloud with it's normal
// Build the co variance matrix
Eigen::Matrix<double, 3, 3> S = gridPnts.transpose() * gridPnts;
S /= static_cast<pilType>(gridPnts.rows() - 1);
Eigen::SelfAdjointEigenSolver<pilMat3> es(S);
Eigen::Matrix<pilType, 3, 2> trans;
trans = es.eigenvectors().block<3, 2>(0, 1);
// convert the point cloud to 2D for Convex Hull calculation
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> output(gridPnts.rows(), 2);
output = gridPnts * trans;

我正在使用GCC 5.3.0编译新版本,标志-std = c ++ 11 -O3 -DEIGEN_NO_DEBUG -Wall -Wextra -Werror -march = native -mtune = native。我已经尝试过是否带有进行曲和调整选项。旧版本使用GCC 4.3.4和标志-O3 -DEIGEN_NO_DEBUG -Wall -Wextra -Werror编译。 CPU是运行SuSE Enterprise SLES 11的SandyBridge E5-2670。区别在于S除以点数-1之后开始。它们很小,大约为1e-12,但是当它出现时对于本征解,非常接近0的值可能会导致本征向量的符号改变。这导致转换矩阵在一个轴上切换。结果输出沿该轴翻转。将生成的2D补丁发送到例程以查找凸包。返回相同的点,但由于轴翻转而以相反的顺序返回。这不是错误,但出乎意料。

实际上,在整个应用程序中,各种数字在1e-12至1e-15范围内显示出差异。

在使用GDB运行时,有一些值(最高值来自3.3.4版,最低值来自3.2.0版)

S除法之前:

    Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb0b0) = {[0,0] = 3532221.7020642869,
  [1,0] = 1.0913936421275139e-11, [2,0] = 3332.4628071428679, [0,1] = 1.0913936421275139e-11,
  [1,1] = 335265.83999999962, [2,1] = -1.3073986337985843e-12, [0,2] = 3332.4628071428679,
  [1,2] = -1.3073986337985843e-12, [2,2] = 4697.4509785714226}

Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb8f0) = {[0,0] = 3532221.7020642869,
  [1,0] = 1.0913936421275139e-11, [2,0] = 3332.4628071428679, [0,1] = 1.0913936421275139e-11,
  [1,1] = 335265.83999999962, [2,1] = -1.3073986337985843e-12, [0,2] = 3332.4628071428679,
  [1,2] = -1.3073986337985843e-12, [2,2] = 4697.4509785714226}

S除后

Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb0b0) = {[0,0] = 21151.028156073575,
  [1,0] = 6.5352912702246338e-14, [2,0] = 19.954867108639927, [0,1] = 6.5352912702246338e-14,
  [1,1] = 2007.5798802395186, [2,1] = -7.8287343341232597e-15, [0,2] = 19.954867108639927,
  [1,2] = -7.8287343341232597e-15, [2,2] = 28.128448973481571}

Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb8f0) = {[0,0] = 21151.028156073575,
  [1,0] = 6.5352912702246351e-14, [2,0] = 19.954867108639927, [0,1] = 6.5352912702246351e-14,
  [1,1] = 2007.5798802395188, [2,1] = -7.8287343341232597e-15, [0,2] = 19.954867108639927,
  [1,2] = -7.8287343341232597e-15, [2,2] = 28.128448973481575}

在执行本征解之后,trans的值是:

{[0,0] = 3.4096942364292876e-18, [1,0] = -1,
  [2,0] = 3.9893751393767394e-18, [0,1] = 0.99999955376919869, [1,1] = 3.4134614846087836e-18,
  [2,1] = 0.00094470175363752104}

{[0,0] = 0, [1,0] = 1,
  [2,0] = -3.2750362278258563e-15, [0,1] = 0.9999995537691988, [1,1] = 3.093932467653499e-18,
  [2,1] = 0.00094470175363752125}

公认的数值差异很小,并且在准确性的范围内。在所示的数字中,转换矩阵的符号翻转,从而导致2D云翻转。是否有办法清理所做的工作,以消除这些差异?我见过一些Eigen函数,这些函数的阈值较小,但没有除法函数。

2 个答案:

答案 0 :(得分:2)

您根本不应该依赖特征向量的符号(无论求解器和库如何),而应根据需要进行调整。例如,如果您想确保有一个惯用右手的基础,请从前两个叉号的叉积更新最后一个。

答案 1 :(得分:0)

Eigen用version 3.2.7计算标量除法的方式发生了变化。

  

operator / =(Scalar)现在执行真正的除法(而不是mat *(1 / s))

使用S *= 1.0 / (static_cast<pilType>(gridPnts.rows() - 1));测试代码表明数字差异已解决。